Cloudbleed 2017 : fuite mémoire d’un proxy TLS mutualisé
Section intitulée « Cloudbleed 2017 : fuite mémoire d’un proxy TLS mutualisé »En février 2017, Tavis Ormandy (Google Project Zero) remarque que des réponses servies par Cloudflare contiennent des morceaux de mémoire appartenant à d’autres sites : cookies, jetons d’authentification, corps de requêtes POST. La cause est une lecture hors limites dans un analyseur HTML (HyperText Markup Language) du proxy de périphérie, à un endroit où le trafic de milliers de clients était déjà déchiffré. Le cas illustre de façon exemplaire le prix caché de la terminaison TLS (Transport Layer Security) chez un tiers mutualisé.
Imagine un guichet de poste qui ouvre toutes les lettres pour y coller un tampon avant de les refermer, toutes sur la même table. Un jour, une erreur de rangement fait glisser dans ton enveloppe des pages arrachées aux lettres des autres clients. Ce guichet rend service à tout le monde, et c’est justement pour ça qu’une seule maladresse touche tout le monde.
→ Lire l’explication complète de la marmotte
Le bug Cloudbleed : un analyseur HTML qui lit au-delà de son tampon
Section intitulée « Le bug Cloudbleed : un analyseur HTML qui lit au-delà de son tampon »Le proxy de périphérie d’un CDN (Content Delivery Network) ne se contente pas de relayer des octets. Pour offrir des fonctions de réécriture (masquage des adresses e-mail contre les robots collecteurs, réécriture automatique des liens http:// en https://, exclusion de fragments de page côté serveur), il analyse le HTML de la réponse de l’origine, le modifie, puis le renvoie. Cette analyse s’exécute dans les processus de travail du serveur web de périphérie, construit sur NGINX, qui traitent en même temps les requêtes de nombreux sites clients.
L’analyseur en cause était généré par Ragel, un outil qui compile une machine à états en code C. La condition de fin de tampon y était écrite sous la forme if (++p == pe) : le pointeur de lecture p ne s’arrêtait que s’il tombait exactement sur la fin pe. Sur certaines pages se terminant par une balise ou un attribut non refermé, une transition faisait sauter p au-delà de pe. Le test d’égalité ne se déclenchait plus, et la lecture continuait dans le tas, en recopiant dans la réponse ce qui traînait derrière. Un >= à la place du == suffisait à rendre l’erreur inoffensive ; les défauts les plus coûteux tiennent rarement en plus d’un caractère.
Le défaut existait depuis longtemps dans le code généré. Il est devenu exploitable lorsque l’introduction d’un nouvel analyseur a modifié la gestion des tampons transmis à l’ancien. Le code n’avait pas changé ; son contexte, si. Cloudflare situe le premier débordement possible au 22 septembre 2016 ; Ormandy le signale le 17 février 2017. Les fonctions fautives sont désactivées dans l’heure, le correctif complet est déployé en quelques heures, la divulgation publique intervient le 23 février.
La classe de faute est connue et cataloguée : lecture hors limites, CWE-125 dans la CWE (Common Weakness Enumeration). Rien d’exotique. C’est d’ailleurs le point : la faute la plus banale du C, placée à l’endroit le plus mal choisi.
Terminaison TLS mutualisée : pourquoi une page révèle les secrets d’un autre site
Section intitulée « Terminaison TLS mutualisée : pourquoi une page révèle les secrets d’un autre site »La gravité ne vient pas du dépassement lui-même, mais de ce qui se trouvait dans la mémoire adjacente. Un proxy qui termine TLS détient le trafic en clair : en-têtes Cookie et Authorization, corps de requêtes POST, réponses d’API (Application Programming Interface). Un processus de travail mutualisé mélange dans son tas les requêtes de clients qui n’ont aucun lien entre eux. Le site A, avec du HTML mal formé et une fonction de réécriture active, servait de déclencheur ; le site B, qui n’avait rien activé de particulier, fournissait la matière.
Le schéma suivant montre la séquence : la victime n’est pas le site déclencheur, et le dernier destinataire n’est pas un attaquant mais un robot d’indexation.
Ce qu’il faut y lire : aucune étape ne nécessite d’attaquant. Il suffit d’un visiteur quelconque d’une page déclenchante pour recevoir les secrets d’un tiers, et les caches des moteurs de recherche ont fait le reste en archivant ces réponses. Les fragments ont été retrouvés dans les caches de plusieurs moteurs, qu’il a fallu purger un par un. Une fuite qui s’auto-publie : l’industrie appelle ça « distribution mondiale », dans un autre contexte.
La topologie ci-dessous situe le point de rupture : les deux liens sont chiffrés, et c’est précisément entre eux, dans le proxy, que tout passe en clair.
Le compromis de la terminaison TLS en périphérie
Section intitulée « Le compromis de la terminaison TLS en périphérie »Le compromis central se formule sans détour. Terminer TLS chez un fournisseur de périphérie apporte le cache, l’absorption des attaques volumétriques, le WAF (Web Application Firewall) et la réécriture de contenu ; on paie en confiant le texte clair de chaque session à un logiciel tiers, mutualisé, écrit dans un langage où une erreur d’indice lit la mémoire du voisin. Le cadenas du navigateur certifie la connexion jusqu’au proxy. Au-delà, il ne certifie rien, et ne l’a jamais prétendu.
La position défendue ici : la terminaison en périphérie reste le bon choix pour le contenu public et la protection contre le déni de service, à condition de traiter le proxy mutualisé comme une zone où un secret peut fuir, et d’organiser les secrets en conséquence. Concrètement :
- Séparer les noms d’hôte par sensibilité. Le site vitrine profite de toutes les fonctions de réécriture ; le domaine d’authentification et l’API n’en activent aucune. Cloudbleed n’exigeait la réécriture que sur le site déclencheur, donc cette séparation ne protège pas ses propres secrets d’un voisin négligent ; elle réduit en revanche la probabilité d’être soi-même le déclencheur, et la surface de code qui touche aux réponses sensibles.
- Raccourcir la vie des secrets en transit. Un jeton d’accès de quinze minutes fuité dans un cache public vaut moins qu’un cookie de session de trente jours. La durée de vie d’un jeton est la seule contre-mesure qui agit après la fuite sans intervention humaine.
- Lier les jetons à leur porteur. Un jeton lié à une clé du client (DPoP, Demonstrating Proof of Possession, ou liaison à un certificat client) ne se rejoue pas tel quel depuis un fragment de mémoire.
- Chiffrer au niveau applicatif ce qui ne doit jamais apparaître en clair chez un tiers. Numéros de carte, pièces d’identité, secrets de récupération : chiffrés côté client avec une clé publique de l’origine, ils transitent opaques dans le proxy.
- Réserver le passage TCP (Transmission Control Protocol) brut ou une terminaison dédiée aux flux dont le texte clair ne doit jamais toucher une mémoire mutualisée, en renonçant alors au WAF et au cache pour ces flux.
La question qui tranche entre terminaison mutualisée et terminaison dédiée n’est pas « le fournisseur est-il sérieux ? », mais « que vaut un secret de ce flux s’il apparaît dans la réponse d’un inconnu ? ». Si la réponse se compte en sessions à révoquer, la mutualisation se défend. Si elle se compte en données qui ne se révoquent pas (état civil, pièces justificatives, secrets de récupération), elle ne se défend plus.
La page voisine sur la terminaison TLS dans un load balancer cloud traite la configuration de l’équipement lui-même ; celle-ci traite le risque de mutualiser le texte clair.
Surface d’attaque d’un proxy de périphérie qui termine TLS
Section intitulée « Surface d’attaque d’un proxy de périphérie qui termine TLS »Cloudbleed n’est qu’une famille parmi celles qui visent ce composant. Un proxy qui voit le clair et partage sa mémoire concentre plusieurs surfaces :
| Surface | Attaque connue | Contre-mesure côté fournisseur | Contre-mesure côté client |
|---|---|---|---|
| Analyse et réécriture du contenu | Lecture hors limites (Cloudbleed, CWE-125) | Analyseurs en langage à mémoire sûre, fuzzing continu, isolation des processus par client | Désactiver les réécritures sur les hôtes sensibles |
| Bibliothèque TLS | Divulgation mémoire de type Heartbleed (OpenSSL, 2014) | Mise à jour rapide, bibliothèques à mémoire sûre | Rotation des clés privées après tout avis de ce type |
| Clé de cache | Tromperie de cache, voir l’attaque de cache deception | Clés de cache incluant le type de contenu | Cache-Control: private, no-store sur toute réponse authentifiée |
| Routage et normalisation | Confusion de préfixe, voir la confusion de préfixe de chemin ; injection d’en-tête Host | Normalisation unique et documentée | Origine qui refuse tout Host non attendu |
| Lien proxy vers origine | Contournement du proxy en atteignant l’origine directement | mTLS (mutual TLS) vers l’origine | Origine qui n’accepte que le certificat client du proxy |
Un point mérite d’être martelé : les dispositifs qui gardent la clé privée hors du fournisseur (clé conservée dans un HSM (Hardware Security Module) chez le client, signature à distance de la poignée de main) protègent la clé, pas la session. Avec une clé privée parfaitement isolée, le proxy reçoit quand même les clés de session et le texte clair. Cloudbleed n’a touché aucune clé privée et n’en avait pas besoin. Le HSM refuse de laisser sortir une clé ; il n’a jamais promis d’empêcher un cookie de fuiter par une autre porte.
Ce que TLS et le fournisseur ne garantissent pas
Section intitulée « Ce que TLS et le fournisseur ne garantissent pas »TLS, y compris dans sa version 1.3 décrite par la RFC 8446, garantit la confidentialité et l’intégrité entre deux extrémités. Quand le proxy est une extrémité, la garantie s’arrête à lui. Elle ne dit rien :
- de l’isolation mémoire entre clients d’une même instance mutualisée ;
- de la qualité du code qui transforme les réponses ;
- de ce que deviennent les réponses une fois émises (caches de navigateurs, de moteurs, d’archives web, de proxys d’entreprise) ;
- de la durée pendant laquelle un secret fuité reste utilisable.
Le reste doit venir d’ailleurs : de l’application (durée de vie et liaison des jetons, chiffrement applicatif), du contrat (délai de notification, liste des fonctions qui touchent au contenu) et de l’exploitation (capacité à tout révoquer). Un fournisseur peut corriger son code en quelques heures ; il ne peut pas invalider les sessions de ses clients à leur place, ni savoir lesquels de leurs secrets valaient quelque chose. Après Cloudbleed, la purge des caches publics a été menée par le fournisseur, mais la rotation des secrets, elle, revenait à chaque client.
Exemple : arbre de décision après l’annonce d’une fuite mémoire du proxy
Section intitulée « Exemple : arbre de décision après l’annonce d’une fuite mémoire du proxy »Le jour où un fournisseur de périphérie annonce une divulgation de mémoire, la tentation est d’attendre de savoir si son propre domaine figure dans la liste des sites affectés. C’est une erreur de raisonnement héritée de Cloudbleed lui-même : la liste publiée désigne les sites déclencheurs, pas les sites victimes. Tout client dont le trafic transitait par les instances concernées pendant la période est potentiellement exposé.
Lecture de l’arbre : la seule branche qui ne coûte rien est celle des jetons dont la durée de vie est déjà écoulée. Tout le reste coûte une révocation, donc une déconnexion forcée des utilisateurs, ou une notification. C’est l’argument le plus convaincant pour des jetons courts : ils transforment un incident de crise en ligne d’archive. La branche « Notification » renvoie à l’article 33 du règlement (UE) 2016/679 (RGPD, Règlement général sur la protection des données) pour le délai de notification ; savoir si une fuite donnée constitue une violation notifiable relève d’une analyse juridique propre à chaque responsable de traitement.
La recherche dans les caches publics repose sur un préalable souvent oublié : connaître des motifs propres au service (préfixe des clés d’API, nom du cookie de session, format des identifiants internes). Un préfixe distinctif sur les secrets (svc_live_ plutôt qu’une chaîne hexadécimale anonyme) rend la recherche faisable et permet aux outils de détection de secrets de les reconnaître.
Conditions d’exploitation d’une terminaison TLS mutualisée
Section intitulée « Conditions d’exploitation d’une terminaison TLS mutualisée »Mettre un proxy mutualisé devant un service n’est défendable que si les capacités suivantes existent avant l’incident, pas après :
Prérequis. Un inventaire des hôtes servis par le fournisseur, avec pour chacun les fonctions de transformation activées. Les consoles de CDN accumulent les options activées « pour voir » comme un grenier accumule les cartons : personne ne sait ce qu’il y a dedans, mais rien ne sort. Une configuration décrite en code (Terraform ou équivalent) et versionnée rend cet inventaire vérifiable.
Rotation. La capacité de révoquer en masse toutes les sessions et tous les jetons d’un service, en une opération testée. Un mécanisme de révocation jamais exercé échoue de façon fiable le jour où il sert : changement de clé de signature des jetons sans période de recouvrement, clients mobiles qui ne savent pas se réauthentifier, clés d’API de partenaires codées en dur. Les clés d’API transmises en en-tête à travers le proxy doivent avoir une procédure de remplacement coordonnée avec les partenaires, rédigée avant d’en avoir besoin.
Supervision. Des jetons canaris (identifiants factices injectés dans le trafic réel, qui ne servent à rien sauf à déclencher une alerte quand on les utilise) détectent un usage de secrets fuités, quel que soit le canal de la fuite. La journalisation des authentifications doit permettre de distinguer un jeton émis avant et après une date donnée, sinon l’analyse de la période d’exposition devient impossible.
Sauvegarde et reprise. Une capacité de bascule documentée vers une terminaison TLS hors du fournisseur (équilibreur propre, certificat et clé disponibles hors du CDN) pour les hôtes critiques. Elle sert autant contre une fuite que contre une panne du fournisseur, et elle n’existe en pratique que si le certificat de l’origine est valide pour le nom public et si l’origine encaisse le trafic sans le cache.
Contrat. Un délai de notification des incidents de sécurité, la liste des fonctions qui analysent ou modifient le contenu, et le droit d’obtenir la période d’exposition précise. Pour les entités soumises à la directive NIS 2, la gestion de ce fournisseur relève de la sécurité de la chaîne d’approvisionnement (article 21) ; la page sur la gestion des risques tiers traite ce cadre.
- RFC 8446 : The Transport Layer Security (TLS) Protocol Version 1.3, IETF, août 2018.
- CWE-125, MITRE.
- Règlement (UE) 2016/679 du Parlement européen et du Conseil du 27 avril 2016 relatif à la protection des personnes physiques à l’égard du traitement des données à caractère personnel et à la libre circulation de ces données (RGPD), Union européenne, avril 2016.
- Directive (UE) 2022/2555 du Parlement européen et du Conseil du 14 décembre 2022 concernant des mesures destinées à assurer un niveau élevé commun de cybersécurité dans l’ensemble de l’Union (directive SRI 2 / NIS 2), Union européenne, décembre 2022.
🐝 Ce qui arrive si on s’en passe
Section intitulée « 🐝 Ce qui arrive si on s’en passe »Sans séparation des hôtes sensibles ni jetons courts, une divulgation mémoire chez le fournisseur expose des sessions valides pendant des semaines : chaque cookie retrouvé dans un cache public ouvre un compte sans mot de passe ni second facteur, puisque l’authentification a déjà eu lieu. Sans procédure de révocation en masse testée, la réponse se limite à forcer le changement de mot de passe, qui n’invalide pas forcément les sessions établies. Sans jetons canaris ni journalisation datée des émissions, impossible de savoir si un secret fuité a servi, donc impossible de borner l’incident ou d’étayer une notification. Sans terminaison de repli, la seule option pendant l’analyse reste de continuer à faire transiter le texte clair par le composant défaillant.
🦫 Explication de la marmotte 🍫
Section intitulée « 🦫 Explication de la marmotte 🍫 »Quand tu visites un site, ta connexion est chiffrée : personne sur le trajet ne peut lire ce que tu envoies. Mais beaucoup de sites passent par un intermédiaire, un serveur d’une grande entreprise qui reçoit ta connexion, la déchiffre, garde des copies des pages pour aller plus vite, puis renvoie la demande au vrai site. Chez cet intermédiaire, tes données sont donc lisibles, et elles sont rangées dans la mémoire de l’ordinateur juste à côté de celles de milliers d’autres personnes visitant d’autres sites. En 2017, un programme de cet intermédiaire, chargé de modifier le texte de certaines pages, contenait une erreur : quand une page se terminait de façon incomplète, il ne s’arrêtait pas à la fin et continuait à lire la mémoire voisine. Ce qu’il lisait était ajouté à la page envoyée. Résultat : des inconnus recevaient des morceaux de connexions d’autres gens, avec leurs codes de connexion. Des moteurs de recherche ont enregistré ces pages, qu’il a fallu effacer. L’entreprise a corrigé l’erreur en quelques heures, mais chaque site devait ensuite déconnecter ses utilisateurs pour rendre inutiles les codes volés. Ce qui limite les dégâts : des codes qui expirent vite, des informations très sensibles chiffrées une seconde fois avant d’arriver chez l’intermédiaire, et une méthode prête pour tout annuler d’un coup.
À lire aussi
- Attaque MIME sniffing par fichier téléverséDémonstration d’une confusion de type MIME où un fichier téléversé est interprété comme du HTML ou du JavaScript exécutable faute de protection de type stricte.
- Cross-site scripting (XSS) : mécanisme, variantes et défensesComprendre le cross-site scripting (XSS), ses variantes réfléchie, stockée, DOM et par mutation, et les défenses qui tiennent réellement en production.
- Faille Facebook Voir en tant que 2018 et vol de jetons d'accèsAnalyse de la faille Facebook Voir en tant que de septembre 2018, où trois bogues enchaînés ont livré des jetons d'accès, et de ce qu'elle impose à l'émission et à la révocation des jetons.
- CWE-79 : cross-site scripting, la classe au premier rang du Top 25CWE-79, neutralisation incorrecte des entrées lors de la génération d'une page web : ce que la classe recouvre, sa place dans l'arbre CWE, ses sept variantes, et pourquoi elle arrive première du Top 25 2025.
Pages voisines
La citent
- Spectre et Meltdown : exécution spéculative et fuite par cache
- CWE-125 : lecture hors limites, la fuite qui ne casse rien
Cloudbleed 2017 : fuite mémoire d'un proxy TLS mutualisé
Elle cite
- Lien dans les deux sens :Sécuriser un load balancer cloud et la terminaison TLS
- Attaque cache deception CDN et contre-mesures
- Comment prévenir une attaque Host header injection
- Contourner un contrôle proxy par confusion de chemin
- Délais de notification d’incident NIS2 RGPD DORA
- Gérer les risques tiers et la chaîne logicielle
: les deux pages se citent l’une l’autre.
