Retour sur les attaques DDoS record de type HTTP/2 « Rapid Reset »
Daniele Iamartino
Staff Site Reliability Engineer
Juho Snellman
Staff Software Engineer
Contactez-nous
Si vous êtes une entreprise et que vous souhaitez vous développer, découvrez comment gagner en productivité avec Google Cloud ou contactez notre équipe commerciale.
Commencer iciComme nous l’évoquions dans un récent post Blog, un certain nombre de services et de clients Google Cloud ont été ciblés par de nouvelles attaques DDoS massives basées sur le protocole HTTP/2. Des attaques qui ont atteint leur paroxysme en août en surpassant les 398 millions de requêtes par seconde, un nouveau record. Ces attaques sont très significativement plus massives que toutes les précédentes attaques impactant la couche 7 du modèle OSI.
Ces attaques ont, pour l’essentiel, été directement bloquées à la périphérie même par notre infrastructure mondiale d'équilibrage de charge et n'ont pas entraîné de pannes.
Bien que l'impact sur nos services et clients ait été minime, la DDoS Response Team (l'équipe de réponse DDoS) de Google a été mobilisée, examinant les attaques et ajoutant des protections supplémentaires afin d'atténuer davantage encore les attaques similaires. Outre cette réponse interne de Google, nous avons également activement contribué à mener un processus de divulgation coordonné avec les partenaires de l'industrie pour traiter le nouveau vecteur HTTP/2 – utilisé par ces attaques – dans l'ensemble de l'écosystème cloud et IT.
Ces nouvelles vagues DDoS sont une opportunité de revenir dans cet article sur les méthodologies des « attaques sur la couche 7 », employées par les cyberattaquants ces dernières années. Nous allons ici expliquer ce qui différencie cette nouvelle vague et la rend bien plus importante. Nous allons aussi revenir sur les stratégies d’atténuation que nous croyons les plus efficaces pour lutter contre ce type de menaces.
Pour cela, nous adopterons ici essentiellement le point de vue d’une architecture de proxy inverse, où la requête est bloquée par un proxy inverse qui transmet en temps normal les requêtes vers d’autres services. Les mêmes concepts s’appliquent cependant aux serveurs HTTP intégrés aux serveurs d’applications avec des considérations un peu différentes qui peuvent conduire à des stratégies d’atténuation différentes.
Des attaques DDoS sur HTTP/2
Depuis fin 2021, la majorité des attaques DDoS sur la couche 7 - menées contre les services Google et projets Google Cloud protégés par Cloud Armor - s’appuient sur HTTP/2. C’est vrai à la fois en termes de nombre d'attaques que de pics atteints par le volume de requêtes !
L'un des principaux objectifs du protocole HTTP/2 était l'efficacité. Malheureusement, les fonctionnalités qui rendent HTTP/2 plus efficaces pour les usages légitimes peuvent également être utilisées pour rendre les attaques DDoS plus dangereuses.
Le multiplexage de flux
HTTP/2 utilise des « streams » (des « flux » en bon Français). Ce sont des abstractions bidirectionnelles utilisées pour transmettre divers messages, ou « frames » (des « trames » en Français), entre les points d'extrémité.
Le « multiplexage des flux » est la principale caractéristique de HTTP/2. C’est essentiellement elle qui procure une bien meilleure utilisation de la bande passante de chaque connexion TCP. Les flux sont multiplexés de manière à pouvoir être simultanément suivis par les deux côtés de la liaison tout en n'utilisant qu'une seule connexion « Layer 4 » (couche 4 du modèle OSI). Le multiplexage des flux permet aux clients d'avoir plusieurs requêtes « en vol » (en cours de transfert) sans avoir à gérer plusieurs connexions HTTP individuelles.
Dans le protocole HTTP/1.1, chaque demande est traitée en série (l’une après l’autre). Le serveur lit une demande, la traite, écrit une réponse, puis lit et traite la demande suivante. En pratique, cela signifie que le taux de requêtes pouvant être envoyées sur une seule connexion est d'une requête par aller-retour. Le temps de cet aller-retour dépend notamment de la latence du réseau, du temps de traitement du proxy et du temps de traitement de la requête par le backend. Bien que le pipelining HTTP/1.1 soit disponible dans certains clients et serveurs pour augmenter le débit d'une connexion, il est peu répandu.
À l’inverse, en HTTP/2, chaque client peut ouvrir plusieurs flux simultanément, chaque flux représentant une requête HTTP. Le nombre maximal de flux ouverts simultanément est, en théorie, contrôlable par le serveur, mais dans la pratique, les clients peuvent ouvrir 100 flux par demande et les serveurs traitent ces demandes en parallèle. Il est important de noter que les limites du serveur ne peuvent pas être ajustées unilatéralement, ce qui explique cette pratique généralisée de 100 flux max par demande.
En pratique, un client peut donc ouvrir 100 flux simultanément et envoyer une requête sur chacun d’eux d’un seul coup (plus exactement en un seul « aller-retour). Chaque requête n’est pas directement reçue par le serveur mais par un Proxy (un intermédiaire qui traite les demandes et les redirige vers un serveur disponible). Ce dernier lit et traite chaque flux en série mais les requêtes ensuite redirigées vers les serveurs dorsaux sont à nouveau parallélisées. Au fur et à mesure qu’il reçoit des réponses à ses demandes, le client peut alors ouvrir de nouveaux flux. Cela donne un débit effectif pour une seule connexion de 100 demandes par tour (par aller-retour), avec des temps d’échange similaires à ceux des demandes HTTP/1.1. Dit autrement, chaque connexion TCP est presque 100 fois plus dense (100 fois mieux utilisée).
L'une des principales contraintes lors de l'organisation d'une attaque DDoS sur la couche 7 est le nombre de connexions de transport simultanées. Chaque connexion a un coût, notamment en matière de mémoire allouée au système d'exploitation pour les enregistrements et les tampons des sockets mais aussi de temps CPU pour la « poignée de main TLS » (ou handshake TLS, processus de démarrage de toute session de communication chiffrée TLS). De plus, chaque connexion nécessite un « quatre tuples » unique, c’est-à-dire une paire d’adresses IP et de ports pour chaque côté de la connexion, ce qui limite le nombre de connexions simultanées possibles entre deux adresses IP.
L’attaque « HTTP/2 Rapid Reset »
Ces bases acquises, entrons maintenant un peu plus dans le vif du sujet et le fonctionnement des nouvelles attaques DDoS s’appuyant sur le protocole HTTP/2. Ce dernier permet aux clients d'indiquer au serveur qu'un flux précédent doit être annulé en envoyant une trame RST_STREAM. Le protocole n'exige pas que le client et le serveur coordonnent l'annulation de quelque manière que ce soit, le client peut le faire unilatéralement. Le client peut également supposer que l'annulation prendra effet immédiatement lorsque le serveur recevra la trame RST_STREAM, avant que toute autre donnée de cette connexion TCP ne soit traitée.
La nouvelle attaque en vogue est appelée « Rapid Reset » (réinitialisation rapide) parce qu'elle repose sur la capacité d'un point d'extrémité (un client) à envoyer une trame RST_STREAM immédiatement après avoir envoyé une trame de demande. L'autre point d'extrémité (le serveur) commence dès lors à travailler avant d’être contraint de réinitialiser rapidement la demande. Bien que la requête soit effectivement annulée, la connexion HTTP/2 reste néanmoins ouverte. Dès lors, en envoyant un tel signal, une telle trame, le client récupère immédiatement la possibilité d’ouvrir un nouveau flux sur la même connexion.
Comparaison visuelle des flux de requêtes et réponses entre HTTP/1.1 et HTTP/2
L'attaque HTTP/2 Rapid Reset qui exploite ce potentiel est simple : Le client ouvre un grand nombre de flux en même temps comme dans une attaque HTTP/2 standard, mais au lieu d'attendre une réponse du serveur ou du proxy à chaque flux de demande, il annule immédiatement chaque demande.
Cette possibilité de réinitialiser immédiatement les flux permet au final à chaque connexion d'avoir un nombre indéfini de demandes en cours. En annulant explicitement les demandes, l'attaquant ne dépasse jamais la limite des 100 flux ouverts simultanés. Le nombre de requêtes « en vol » (en cours de transfert) ne dépend donc plus du temps d'aller-retour (RTT) puisque le client n’attend aucun retour, mais uniquement de la largeur de bande passante disponible sur le réseau.
Le problème, c’est que dans une implémentation classique de HTTP/2 côté serveur, le serveur demeure contraint de réaliser un travail significatif pour chaque requête bien qu’elles aient été annulées côté client : allouer de nouvelles structures de données pour chaque flux, analyser la requête de départ, décompresser l’entête, mapper l’URL à une ressource, etc. Dans bien des implémentations de Proxy inversé (Reverse Proxy), la demande se retrouve transmise au serveur final avant que la trame RST_STREAM ne soit traitée.
Comme du côté client, l’envoi de demandes ne coûte presque rien (en termes de ressources), il en résulte une asymétrie des « coûts de ressources » qui peut être exploitée pour mener une attaque DDoS.
D’autant que le client dispose d’un autre avantage sur l’infrastructure serveur : l'annulation explicite des demandes immédiatement après leur création implique que le Reverse Proxy n'enverra aucune réponse à ses demandes. L'annulation des demandes avant qu'une réponse ne soit écrite réduit la bande passante de la liaison descendante (du serveur/proxy à l'attaquant). Les attaques peuvent donc être menées aisément depuis une multitude de clients disposant d’une faible bande passante.
Variantes de l'attaque HTTP/2 Rapid Reset
Dans les semaines qui ont suivi les premières vagues DDoS cet été, nous avons vu apparaître quelques variantes d'attaques Rapid Reset. Ces variantes ne sont généralement pas aussi efficaces que la version initiale, mais peuvent néanmoins être plus efficaces que les attaques DDoS HTTP/2 standard.
La première variante n'annule pas immédiatement les flux, mais ouvre un lot de flux à la fois, attend un certain temps, puis annule ces flux et ouvre immédiatement un autre lot important de nouveaux flux. Cette attaque permet de contourner les mesures d'atténuation uniquement basées sur le taux de trames RST_STREAM entrantes (comme autoriser un maximum de 100 RST_STREAM par seconde sur une connexion avant de la fermer). Une défense souvent rapidement mise en place après les premières attaques.
Parce qu’elles ne maximisent pas l’utilisation de la connexion, cette variante de l’attaque Rapid Reset perd le principal atout des attaques par annulation rapide mais se révèle néanmoins plus efficace que les attaques HTTP/2 classiques. Cette variante signifie toutefois que toute mesure d'atténuation basée sur la limitation du débit des annulations de flux doit fixer des limites assez strictes pour être efficace.
La seconde variante se passe complètement du mécanisme d'annulation des flux, et tente plutôt de manière optimiste d'ouvrir plus de flux simultanés que ce que le serveur a signalé pouvoir gérer. L'avantage de cette approche par rapport à l'attaque DDoS HTTP/2 standard est que le client peut garder le pipeline de requêtes plein à tout moment. Dit autrement, il y a toujours un grand nombre de requêtes en attente d’être traitées par le serveur. Cela permet d’éliminer le délai d’aller-retour RTT entre le client et le proxy et d’éviter qu’il ne devienne un goulot d'étranglement à même de limiter la portée de l’attaque. Si la requête concerne une ressource à laquelle le serveur HTTP/2 peut répondre immédiatement, cette variante permet également d’éliminer le RTT entre le proxy et le serveur et donc d’éviter que ce lien ne devienne lui-même un goulot d’étranglement qui ralentirait l’attaque.
La spécification RFC 9113, qui standardise l’implémentation actuelle de HTTP/2, suggère qu'une tentative d'ouverture d'un trop grand nombre de flux n'invalide que les flux qui ont dépassé la limite, et non l'ensemble de la connexion. Nous pensons que la plupart des serveurs HTTP/2 suivent cette spécification à la lettre en se contentant de ne pas traiter les flux supplémentaires et de garder la connexion active. L’attaquant peut alors continuer à ouvrir de nouveaux streams à mesure que les anciens sont traités et fermés par le serveur. Ce qui permet à cette attaque variante de rester active en vue de surcharger le serveur.
Une approche multidimensionnelle des mesures d'atténuation
Selon nous, le simple blocage des requêtes individuelles n’est pas une mesure d'atténuation viable sur le long terme contre cette catégorie d'attaques. A contrario, nous pensons que toute la connexion TCP dans son ensemble doit être clôturée lorsqu'un abus est détecté.
HTTP/2 fournit un support intégré pour la fermeture des connexions, en utilisant le type de trame GOAWAY. Le RFC définit un processus de fermeture d'une connexion élégant qui implique d'abord l'envoi d'un GOAWAY informatif qui ne fixe pas de limite à l'ouverture de nouveaux flux, et un aller-retour plus tard, l'envoi d'un autre GOAWAY qui, cette fois, interdit l'ouverture de flux supplémentaires.
Malheureusement, cette fermeture en douceur des connexions par GOAWAY n’a pas été pensée pour contrer des attaques et n’est pas mise en œuvre de sorte à résister à des clients malveillants. Cette forme d'atténuation par GOAWAY laisse la connexion vulnérable aux attaques « Rapid Reset » pendant trop longtemps. Elle ne devrait donc pas être utilisée pour construire des mesures d'atténuation car elle n'arrête pas les demandes entrantes. Au lieu de cela, le GOAWAY doit être configuré pour limiter immédiatement la création de nouveaux flux.
Reste la vraie grande question : comment déterminer quelles sont les connexions abusives ? L'annulation des requêtes par le client n'est pas intrinsèquement abusive. La fonctionnalité existe dans le protocole HTTP/2 pour de bonnes raisons et notamment pour aider à mieux gérer le traitement des requêtes. Les situations « légitimes » sont typiquement celles où un navigateur n'a plus besoin d'une ressource qu'il a demandée parce que l'utilisateur a quitté la page, ou les applications utilisant une approche « long polling » (technique qui permet de simuler un mécanisme de Push utilisée lorsqu’un client envoie une requête au serveur mais n’attend pas de réponse immédiate) avec un timeout côté client.
Les mesures d'atténuation pour ce vecteur d'attaque peuvent prendre plusieurs formes, mais elles sont principalement axées sur le suivi des statistiques de connexion et l'utilisation de divers signaux pour déterminer l'utilité de chaque connexion. Par exemple, si une connexion compte plus de 100 demandes dont plus de 50 % sont annulées, elle peut faire l'objet d'une réponse d'atténuation. L'ampleur et le type de réponse dépendent du risque encouru par chaque plateforme, mais les réponses peuvent aller des trames GOAWAY forcées, comme nous l'avons vu précédemment, à la fermeture immédiate de toute la connexion TCP.
Pour atténuer les variantes « sans annulation » de ces attaques HTTP/2, nous recommandons de faire en sorte que les serveurs HTTP/2 ferment systématiquement (ou après un petit nombre de récidives) toute connexion TCP qui cherche à dépasser la limite de flux simultanés.
Et pour les autres protocoles ?
Nous ne pensons pas que ces méthodes d'attaque puissent s'appliquer directement à HTTP/3 (QUIC) en raison des différences de protocole. Par ailleurs, Google ne voit actuellement pas HTTP/3 être utilisé comme vecteur d'attaque DDoS à grande échelle. Malgré cela, nous recommandons aux implémentations de serveurs HTTP/3 de mettre en œuvre de manière proactive des mécanismes visant à limiter la quantité de travail effectuée par une seule connexion de transport, à l'instar des mesures d'atténuation de HTTP/2 évoquées plus haut.
Coordination des efforts
Dès le début de l'enquête de notre DDoS Response Team, en coordination avec les partenaires du secteur de la cybersécurité, il est apparu que ce nouveau type d'attaque pourrait avoir un large impact sur toute entité offrant le protocole HTTP/2 pour ses services. Google a contribué à la mise en place d'un processus coordonné en tirant parti d'un groupe préexistant de divulgation coordonnée des vulnérabilités, qui a été utilisé dans le cadre d'un certain nombre d'autres initiatives par le passé.
Au cours du processus de divulgation, l'équipe s'est attachée à prévenir les grands utilisateurs du protocole HTTP/2, notamment les fournisseurs d’infrastructures et de logiciels de serveur. L'objectif de ces notifications préalables était de développer et de préparer des mesures d'atténuation en vue d'une publication coordonnée. Dans le passé, cette approche a permis de déployer à grande échelle des protections chez tous les fournisseurs de services et d’accélérer la mise à disposition de patchs logiciels pour de nombreuses applications et solutions.
Au cours du processus de divulgation coordonnée, nous avons réservé l’identifiant « CVE-2023-44487 » afin d’agréger et suivre les correctifs apportés aux différentes implémentations du protocole HTTP/2.
Prochaines étapes
Les nouvelles attaques présentées dans cet article peuvent avoir un impact significatif sur les services de toute taille. Tous les fournisseurs de services HTTP/2 devraient donc sans tarder évaluer leur exposition à ce problème. Des correctifs et des mises à jour de logiciels pour les serveurs XEB et les langages de programmation les plus courants sont disponibles dès maintenant ou le seront dans un avenir proche. Nous recommandons d'appliquer ces correctifs dès que possible.
Pour nos clients Google Cloud, nous recommandons d'appliquer les correctifs logiciels dans leurs propres VMs, containers et services et d'activer à la fois les protections « Application Load Balancer » et « Google Cloud Armor », qui protègent depuis longtemps Google et nos utilisateurs existants de Google Cloud Application Load Balancing.