Je suis Charlie

Autres trucs

Accueil

Seulement les RFC

Seulement les fiches de lecture

Mon livre « Cyberstructure »

Ève

RFC 7469: Public Key Pinning Extension for HTTP

Date de publication du RFC : Avril 2015
Auteur(s) du RFC : C. Evans, C. Palmer, R. Sleevi (Google)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF websec
Première rédaction de cet article le 18 avril 2015
Dernière mise à jour le 19 novembre 2019


Depuis que les piratages de Comodo et DigiNotar ont fait prendre conscience du peu de sécurité qu'apportent les certificats X.509, plusieurs solutions ont été proposées pour combler les failles des autorités de certification. La proposition de ce RFC, HPKP (HTTP Public Key Pinning), consistait à permettre à un client d'épingler (to pin) les clés cryptographiques d'un serveur HTTP utilisant TLS, c'est-à-dire à s'en souvenir pendant une durée spécifiée par le serveur. Ainsi, même si un faux certificat est émis par une AC, il ne serait pas accepté. En pratique, HPKP a été peu adopté et semble aujourd'hui en voie d'abandon.

Un exemple plus récent d'un « vrai / faux certificat » (certificat vrai car émis par une AC reconnue, mais faux car émis sans l'autorisation du titulaire du nom de domaine, et dans l'intention de tromper les utilisateurs) est celui du ministère des finances français. Comme souvent avec les certificats mensongers, celui-ci visait Google (je soupçonne fort que le but était de lire le courrier Gmail des employés, mais, à Bercy, on dément, et on affirme que les buts étaient de pouvoir effectuer un filtrage du contenu sur le Web externe, et de passer les flux à l'antivirus) et c'est ce qui explique que cette compagnie soit très présente dans les forums comme l'IETF où on cherche des solutions aux sérieuses faiblesses de X.509. Parmi les solutions élaborées, il y a DANE, qui s'appuie sur le DNS (RFC 6698), mais Google préfère les certificats à la lumière du jour du RFC 6962 et l'épinglage (pinning) des clés, dans ce tout nouveau RFC 7469.

À noter qu'il existe déjà des en-têtes HTTP permettant au serveur de spécifier au client son comportement, comme le HSTS du RFC 6797. Mais l'épinglage de clés est indépendant de HSTS.

L'épinglage fait partie des techniques TOFU (Trust On First Use) : la première fois qu'un client se connecte au serveur, il ne peut pas savoir si la clé est bonne (il doit se fier à la validation X.509, avec ses limites). À la première connexion, le client HTTP (par exemple un navigateur Web) doit espérer qu'il n'y a pas d'homme du milieu ayant réussi à obtenir un faux certificat (pour cette raison, une attaque persistente, comme celle du ministère des finances, citée plus haut, ne serait pas empêchée par l'épinglage). Aux connexions suivantes, le client HTTP pourra par contre vérifier l'identité du serveur, grâce à la clé épinglée, c'est-à-dire gardée en mémoire. Ce n'est pas idéal (imaginez un homme du milieu ayant un faux certificat pour la première connexion et épinglant ses propres clés, empêchant ainsi toute correction ultérieure !) mais c'est un progrès sur la situation actuelle (valider les clés est un problème difficile en cryptographie). À part des clés partagées à l'avance directement entre les correspondants (ce qui ne passerait évidemment pas à l'échelle pour le Web entier), il n'y a pas de solution parfaitement sûre pour la validation des clés.

La section 2 décrit les détails pratiques. Elle définit un nouvel en-tête HTTP, Public-Key-Pins:. Présent dans une réponse HTTPS, cet en-tête indique au client HTTP que ce serait souhaitable qu'il épingle, qu'il mémorise, la clé publique. Le contenu de l'en-tête Public-Key-Pins: est le condensat de la clé publique utilisée pour TLS, condensat encodé en Base64 (RFC 4648). L'algorithme de condensation est indiqué dans la valeur de l'en-tête. Aujourd'hui, c'est forcément SHA-256 (RFC 6234). La clé est l'encodage DER du champ subjectPublicKeyInfo du certificat X.509 (à noter que les cas des clés brutes du RFC 7250 ou des clés PGP du RFC 6091 ne semblent pas traités, car elles n'ont pas les problèmes des certificats X.509). Une directive max-age est obligatoire dans l'en-tête HTTP, pour indiquer le nombre de secondes que doit durer l'épinglage (après quoi le client HTTP « oublie » la clé). Voici un exemple :

Public-Key-Pins: max-age=604800;
       pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM="

Il existe aussi deux directives facultatives. includeSubDomains indique que l'épinglage s'applique aussi aux serveurs dont le nom est un sous-domaine de celui-ci. Si le client se connecte en HTTPS à bar.example.com et reçoit un Public-Key-Pins: avec includeSubDomains, et qu'il se connecte plus tard à foo.bar.example.com, il exigera de trouver la clé épinglée (voir la section 4.2 pour quelques pièges de cette directive). Autre directive facultative, report-uri indique à quel URI le client doit signaler les erreurs résultant de l'épinglage. En effet, on peut prévoir que, comme avec toute technique de sécurité, il y aura des problèmes. Par exemple, des webmestres changeront de clé et oublieront de modifier le Public-Key-Pins:. Il est donc important que ces problèmes soient détectés rapidement. Ce signalement se fera selon la technique décrite plus loin en section 3. Attention aux conséquences pour la vie privée ! La très détaillée section 5 couvre ce risque d'intrusivité. Voici un exemple avec ces deux directives, et l'utilisation de plusieurs clés (par exemple parce qu'un remplacement est en cours) :

Public-Key-Pins: max-age=2592000;
       pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=";
       pin-sha256="LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ=";
       includeSubDomains;
       report-uri="https://other.example.net/pkp-report"

À noter qu'un deuxième en-tête est défini, Public-Key-Pins-Report-Only:, qui a exactement la même syntaxe, mais une sémantique différente : le client HTTP teste la clé épinglée et, si elle est fausse, le signale à l'URI indiqué par report-uri (qui devient donc obligatoire), mais n'empêche pas l'accès au serveur. C'est utile pour tester avant le vrai déploiement. Les deux en-têtes sont désormais dans le registre des en-têtes.

Comme indiqué plus haut, la section 3 décrit la façon dont un client HTTP peut signaler une erreur de validation. Pour cela, le client HTTP doit fabriquer un message en JSON (RFC 8259) et l'envoyer avec la méthode POST de HTTP à l'URI indiqué dans la directive report-uri. Voici un exemple d'un tel message (la date est au format du RFC 3339) :

 {
    "date-time": "2014-04-06T13:00:50Z",
    "hostname": "www.example.com",
    "port": 443,
    "effective-expiration-date": "2014-05-01T12:40:50Z"
    "served-certificate-chain": [
      "-----BEGIN CERTIFICATE-----\n
      MIIEBDCCAuygAwIBAgIDAjppMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT\n
      ...
    ],
    "validated-certificate-chain": [
      "-----BEGIN CERTIFICATE-----\n
      MIIEBDCCAuygAwIBAgIDAjppMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT\n
      ...
    ],
    "known-pins": [
      'pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM="',
      "pin-sha256=\"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=\""
    ]
  }

Comme souvent en sécurité, le diable est dans les détails, et c'est ce qui explique que la section 4, l'obligatoire « Security Considerations » soit particulièrement longue. Par exemple, l'épinglage peut avoir des conséquences néfastes si on s'est fait voler sa clé privée : normalement, on génère une nouvelle clé, un nouveau certificat et on demande à l'AC de re-signer. Mais on ne pourra pas l'utiliser car la clé publique correspondant à la clé volée est toujours épinglée dans des tas de navigateurs. On peut réduire ce problème en diminuant la durée d'épinglage. Mais, alors, on réduit aussi la durée de la protection dans le cas où une AC génère un certificat mensonger. Un compromis est donc nécessaire. Une approche possible est d'épingler, non pas la clé du serveur mais une clé intermédiaire dans la chaîne des certificats. Supposons que la société Example, qui gère example.com soit cliente de l'AC SmallAC qui a elle-même son certificat signé par une AC très largement reconnue, BigAC. En épinglant la clé de SmallAC, on se protège contre un vol de la clé privée d'example.com, et contre un faux certificat, même émis par BigAC. La société Example reste vulnérable à un faux certificat produit par SmallAC mais cela diminue sérieusement le nombre d'acteurs qui peuvent attaquer Example. (Notez que DANE a les mêmes possibilités : on peut publier dans le DNS sa propre clé, ou bien celle d'une AC.)

On a vu plus haut qu'on pouvait avoir plusieurs clés dans l'en-tête Public-Key-Pins:. Une des utilisations de cette possibilité est le cas où on a une clé de réserve (backup pin), non utilisée mais gardée en un endroit différent de la clé du certificat actuel. Ainsi, si, pour une raison ou pour une autre, la clé est inutilisable, la clé de réserve peut prendre le relais immédiatement puisqu'elle est déjà épinglée.

Autre cas où l'épinglage peut avoir un effet néfaste, celui de l'épinglage hostile. Imaginons un méchant qui obtienne un faux certificat. Il détourne le trafic (par exemple par un empoisonnement DNS) et envoie les gens vers son serveur HTTPS, qui semblera légitime, en raison du faux certificat. Avec l'épinglage, il peut même prolonger son attaque en épinglant sa clé. Si le site légitime n'avait pas été visité avant, ou s'il ne faisait pas d'épinglage, l'attaque peut réussir, bloquant le client HTTPS sur la clé de l'agresseur pour la durée max-age spécifiée par ledit agresseur. Il n'y a pas de solution miracle pour ce problème. Une possibilité est de précharger les clés de sites connus dans le navigateur. Une autre est d'utiliser les certificats au grand jour du RFC 6962. (Et, bien sûr, il y a DANE, RFC 6698, que Google prend toujours soin de ne pas mentionner.)

Autres risques, ceux pour la vie privée (section 5). Un serveur peu sympathique peut utiliser l'épinglage comme une sorte de cookie discret. Par exemple, il peut mettre une petite image dans un sous-domaine, épingler des fausses clés pour ce sous-domaine (une différente par visiteur) et attendre les signalements à report-uri pour identifier un client HTTPS unique. Des sites différents peuvent même coopérer pour avoir le même report-uri, pour suivre un client à travers plusieurs sites.

À noter aussi que les signalements d'un problème de validation contiennent la chaîne de certificats utilisée. Cela peut permettre d'identifier l'utilisation de faux certificats par telle ou telle organisation. C'est plutôt une bonne chose pour détecter des attaques comme celle effectuée au ministère des finances mais cela ne sera évidemment pas apprécié de ceux qui veulent faire du détournement de trafic.

Comme toujours en sécurité, l'utilisabilité est cruciale (section 7). Lorsqu'un épinglage a eu lieu, et que le trafic est ensuite détourné vers un faux serveur, le client HTTPS (par exemple le navigateur Web) va refuser l'accès à ce faux serveur ce qui, du point de vue de M. Toutlemonde devant son navigateur, est un déni de service. Il va donc falloir bien expliquer à M. Toutlemonde ce qui se passe, pour éviter qu'il n'accuse le site légitime.

Le RFC recommande aussi que l'utilisateur puisse accéder facilement à la liste des clés épinglées et aussi, ce qui me semble plus contestable, qu'il puisse la modifier, par exemple en désépinglant les clés. Cela me semble dangereux car cela peut ouvrir une voie à l'ingénierie sociale (« il y a un petit problème technique, si l'accès vous est refusé, cliquez sur Clear all pinned keys »).

L'annexe A contient un exemple, utilisant OpenSSL en ligne de commande, pour générer le Public-Key-Pins:. J'en ai fait un petit script qui s'utilise ainsi :

% make-pin.sh www.ietf.org
...
DHKscLdFrBmZiBGxMdZiyaxp29vnyyPltRS1ZmTF09Y=

Et hop, on n'a plus qu'à mettre Public-Key-Pins: max-age=604800; pin-sha256="DHKscLdFrBmZiBGxMdZiyaxp29vnyyPltRS1ZmTF09Y=" dans la réponse du serveur HTTP. (Tom me fait remarquer à juste titre qu'une clé de secours est obligatoire - section 4.3 - et que donc il faut toujours au moins deux pin-sha256. J'ai simplifié.) Les premières versions de l'Internet-Draft qui a mené à ce RFC utilisaient un programme en Go, make-pin.go :

% openssl s_client -servername www.ietf.org -connect www.ietf.org:443 > ietf.pem
...
% ./make-pin ietf.pem 
Hex: 0c72ac70b745ac19998811b131d662c9ac69dbdbe7cb23e5b514b56664c5d3d6
Base64: DHKscLdFrBmZiBGxMdZiyaxp29vnyyPltRS1ZmTF09Y=

À noter que l'annexe B contient quelques conseils pratiques à l'usage des gérants de serveurs HTTPS, sur le bon déploiement de l'épinglage. Par exemple, il est recommandé de commencer doucement, en mode report-only avant de se jeter dans le grand bain et de risquer de bloquer ses clients. Comme avec n'importe quelle technique de sécurité, on risque de se planter soi-même si on ne fait pas attention : n'épinglez pas bêtement !

Question mises en œuvre, Chrome et Firefox avaient déjà de l'épinglage, avec une série de clés mise en dur dans le logiciel (voir la description de Mozilla et leur annonce). Vous pouvez tester ici si votre navigateur gère l'épinglage. Une description de l'épinglage des clés dans Chrome avait été faite par Adam Langley et sa lecture est recommandée (par exemple pour comprendre pourquoi on épingle juste des clés et pas des certificats entiers). Pour le monde Microsoft, voir leur article. Il y aussi un article détaillé sur le concept, chez OWASP, et l'article de Robert Love avec des détails pratiques. Le peu de succès de HPKP fait que Firefox, par exemple, a annoncé son intention de l'abandonner (cf. ticket #1412438.)

Merci à Florian Maury et Kim Minh Kaplan pour leur relecture.


Téléchargez le RFC 7469

Version PDF de cette page (mais vous pouvez aussi imprimer depuis votre navigateur, il y a une feuille de style prévue pour cela)

Source XML de cette page (cette page est distribuée sous les termes de la licence GFDL)