Attention, cet article a plus d'une année d'ancienneté. Il est possible que les informations présentées ne soient plus à jour, spécialement dans le cadre d'un article technique.
Bonjour à tous,
Retour après deux mois de vide rédactionnel, aujourd’hui on va voir ensemble comment déployer HPKP (HTTP Public Key Pinning) avec NGINX et l’autorité de certification Let’s Encrypt.
Prérequis :
- Avoir ma version custom de NGINX (ou le module more headers) : GitHub | Article
- Avoir des certificats ECDSA générés à la main (surtout pour avoir une clé privée qui ne se renouvelle pas automatiquement) : Article
HPKP c’est quoi ?
Vu que Wikipédia a encore fait une bonne description de la chose, on va citer :
HTTP Public Key Pinning (HPKP) est un mécanisme de sécurité qui protège les sites internet de l’usurpation d’identité contre les certificats frauduleux émis par des autorités de certification compromises.
À la première connexion réussie, le site présente une liste représentant les clés de confiances. Le navigateur mémorise cette liste.
Lors des connexions suivantes, si la clé de chiffrement présentée n’est pas présente dans la liste mémorisée, le navigateur refuse la connexion et bloque le site puis s’y reconnecte.
Vous l’aurez compris, c’est moyen dangereux comme histoire et vous aurez vite fait de rendre votre site inaccessible si vous loupez un truc, on va donc voir comment faire pour éviter que ça se produise.
Création des clés de secours :
Première chose, dans le cas où cela merde vous aurez besoin de clés de secours pour créer de nouveaux certificats.
Les algorithmes qui sont déjà acceptés et seront toujours acceptés par les émetteurs de certificats à moyen terme sont :
- le RSA en 4096 bits
- Le ECDSA avec la courbe prime256v1
Créez donc un répertoire pour les clés :
mkdir /tmp/hpkp cd /tmp/hpkp/
Générez la clé RSA et son CSR, rentrez bien le common name :
openssl req -nodes -sha256 -newkey rsa:4096 -keyout "abyssproject.net.rsa.key" -out "abyssproject.net.rsa.csr"
Générez la clé ECDSA et son CSR, rentrez bien le common name :
openssl req -nodes -newkey ec:<(openssl ecparam -name prime256v1) -keyout "abyssproject.net.ec.key" -out "abyssproject.net.ec.csr"
Maintenant, générez les hashs SHA256 des clés publiques :
openssl req -pubkey < abyssproject.net.rsa.csr | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64 openssl req -pubkey < abyssproject.net.ec.csr | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64
Chez moi ça donne ça :
Ih7zlQOi8s4JRJA0Wb/McTpjCc2gLSgJxKWi/a1ewSw= lRaHRedXUsH0Y+OvYYyJhQpwCmBQQusTn9Ts5q2QaEw=
Création du HASH de la clé privée :
Maintenant, rendez vous dans le dossier qui contient la clé privée que vous utilisez actuellement :
cd /etc/letsencrypt/live-ecdsa/abyssproject.net
Et générez le hash SHA256 de la clé publique :
openssl ec -in privkey-p384.pem -outform der -pubout | openssl dgst -sha256 -binary | openssl enc -base64
Chez moi ça donne ça :
ymaHD/rAGZy9JlRlqcc8E36+JCxvW/QduCTbw0BOH+o=
Mise en place dans NGINX et test :
Maintenant, vous pouvez ajouter la ligne suivante dans la partie SERVER de votre vhost :
more_set_headers 'Public-Key-Pins pin-sha256="PIN_LIVE"; pin-sha256="PIN_BACKUP1"; pin-sha256="PIN_BACKUP2"; max-age=10';
Ce qui donne chez moi :
more_set_headers 'Public-Key-Pins pin-sha256="ymaHD/rAGZy9JlRlqcc8E36+JCxvW/QduCTbw0BOH+o="; pin-sha256="Ih7zlQOi8s4JRJA0Wb/McTpjCc2gLSgJxKWi/a1ewSw="; pin-sha256="lRaHRedXUsH0Y+OvYYyJhQpwCmBQQusTn9Ts5q2QaEw="; max-age=10';
Redémarrez NGINX :
service nginx restart
Et vérifiez que le header HPKP s’affiche :
curl -I https://www.abyssproject.net/
Allez sur le site suivant : https://report-uri.io/home/pkp_analyse/ pour vérifier que votre header est correct :
Si tout est bon, remplacez :
max-age=10
Par
max-age=5184000
C’est la recommandation (60 jours) du RFC 7469 qui définit le HPKP : https://tools.ietf.org/html/rfc7469#section-4.1 (début de la page 19)
Et revérifiez :
Sauvegarde de ses clés privées :
Maintenant la grande question de la sauvegarde des clés privées.
- Déjà, ne gardez évidemment pas les clés de secours sur le même serveur.
- Gardez une copie papier et / ou offline chez vous sur une partition chiffrée
- Envoyez une copie chiffrée sur Online.net C14 ou OVH Cloud Archive
- Mettez une copie papier à la banque
En cas de soucis :
Virez le header et patientez 60 jours avant de retrouver vos visiteurs 🙂
Merci à Aeris pour ses conseils éclairés 🙂
Merci pour cet article très intéressant !
Comment cela se passe lorsque nos certificats sont renouvelés ?
Salut, si tu renouvelle juste le certificat tu n’a rien à faire, par contre si tu renouvelle la clé privée, il faudra faire une rotation 6 mois à l’avance.
D’accord merci pour ta réponse. 🙂
Donc rien de spécifique à faire pour un renouvellement, par contre en cas de migration ou réinitialisation de serveur, si l’on veut rien casser il faudra bien veillez à sauvegarder son dossier let’s encrypt pour ne pas changer de clé privée est-ce exact ?
En tout cas cela faisait un moment que je souhaitais mettre cela en place sur mes sites, grâce à toi je vais pouvoir y arriver !