Configurer HTTPS sur Nginx - Angristan
Configurer HTTPS sur Nginx

Configurer HTTPS sur Nginx

Ce billet a été écrit il y a longtemps. Il peut contenir des informations erronées.

Et non, HTTPS ne se résume pas à avoir un cadenas vert dans votre navigateur !

De plus en plus de sites sont compatibles HTTPS, et cela ne va qu’augmenter avec l’arrivée de Let’s Encrypt qui propose des certificats X.509 gratuits tout comme StartSSL. Et même si vous utilisez un certificat auto-signé, votre sécurité reste importante.

Nous allons voir dans ce tutoriel tous les paramètres à ajouter dans votre configuration Nginx pour avoir un chiffrement au top. Certains en ont bien besoin !

Cet article a aussi pour but de vous expliquer partie de la configuration et les différents concepts liés, pas juste un copié/collé d’une conf trouvé sur le web. Cependant, vous pouvez trouver toute la conf à la fin de cet article.

Configurer HTTPS sur Nginx

Tous les paramètres ci-dessous seront à mettre dans votre server block (HTTPS), c’est à dire ici :

server {
# 
# Votre conf
#
}

Redirection et ports

Lorsqu’un visiteur va aller sur votre site web, il va demander à voir la page en HTTP par défaut. Il faut donc rediriger toutes les requêtes HTTP en HTTPS.

server {
       listen         80;
       server_name    domain.com;
       return         301 https://$server_name$request_uri; #Redirection 
}

server {
       listen         443 ssl;
       server_name    domain.com;
       [....]
       # conf HTTPS
}

IPv4 et IPv6

Écouter en IPv4 sur le port HTTPS :

listen 443 ssl;

Écouter en IPv6 sur le port HTTPS :

listen [::]:443 ssl;

SPDY et HTTP/2

SPDY est un protocole développé par Google dont le principal avantage est le multiplexage des connexions, c’est à dire de pouvoir faire plusieurs requêtes HTTP à la fois. SPDY est présent dans sa version 3.1 depuis Nginx 1.5.

Il suffit d’ajouter spdy à la directive listen :

listen 443 ssl spdy;

La version 4 de SPDY n’a pas été aboutie puisqu’elle a servie de base à HTTP/2, qui dispose des même avantages en HTTPS.

Configurer HTTPS sur Nginx

Le module HTTP/2 remplace le module SPDY depuis la version 1.9.5 de Nginx. Il suffit de remplacer spdy par http2 dans la directive listen :

listen 443 ssl http2;

Pour avoir un support complet de HTTP/2 avec ALPN, il faudra compiler Nginx avec OpenSSL 1.0.2, qui n’est pas encore présent dans toutes les distributions.

Pour tester le support de HTTP/2 et de ALPN, vous pouvez utiliser l’outil de test de KeyCDN :

Configurer HTTPS sur Nginx

SSL et TLS

SSL et TLS sont deux protocoles qui permettent d’échanger des données de manière sécurisée.

Ils garantissent :

  • l’authentification du serveur
  • la confidentialité des données
  • l’intégrité des données

Plusieurs versions de SSL et TLS sont disponibles :

  • SSL v1
  • SSL v2
  • SSL v3
  • TLS v1.0
  • TLS v1.1
  • TLS v1.2
  • TLS v1.3 (en cours de développement)

Toutes les versions de SSL sont à proscrire. Elle sont complètement trouées et contiennent de très nombreuses vulnérabilités. TLS 1.0 et et 1.1 sont à éviter également le plus possible. Il n’y presque aucune raison de les utiliser aujourd’hui puisque la quasi-totalité des navigateurs et OS modernes sont compatibles avec (même Windows XP avec Chrome ou Firefox). L’ANSSI recommande également de n’utiliser que TLS (et si possible d’éviter TLS 1.0).

La conf est donc très simple :

ssl_protocols TLSv1.2;

Si vous souhaitez autoriser l’accès à un public ayant de vieux appareils :

ssl_protocols TLSv1.2 TLSv1.1 TLSv1;

Certificat et clé

Après avoir généré votre certificat ou après l’avoir obtenu auprès de votre autorité de certification, vous vous retrouvez avec plusieurs fichiers, dont votre clé et quelques certificats.

ssl_certificate /chemin/vers/cert.pem;
ssl_certificate_key /chemin/vers/key.pem;

Si vous utilisez un certificat obtenu auprès d’une autorité de certification, il faudra ajouter le certificat intermédiaire correspondant dans cert.pem. Je vous conseille de vous référer à la doc pour cette étape.

Exemple pour Let’s Encrypt :

ssl_certificate /etc/letsencrypt/live/domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/domain.com/privkey.pem;

Clé Diffie-Hellman (DH)

L’échange de clé DH est très important puisqu’il permet au serveur et au client de se mettre d’accord sur un secret commun sans qu’un tiers puisse en prendre connaissance.

La clé de base n’est que de 2048 bits, or la NSA recommande d’utiliser des DH d’au moins 3072 bits :

Configurer HTTPS sur Nginx

Nous allons en créer une de 4096 bit :

openssl dhparam -out dh.pem 4096

Puis l’ajouter dans la configuration :

ssl_dhparam /etc/nginx/dh.pem;

Note : si vous utilisez une cipher suite ECDH (conseillé), pas besoin de passer par cette étape.

Elliptic curve Diffie–Hellman (ECDH)

L’échange de clés Diffie-Hellman basé sur les courbes elliptiques est une variante du protocole vu ci-dessus, plus performante et plus sécurisée.

En effet, si l’on utilise ce paramètre :

ssl_ecdh_curve secp521r1;

La clé sera alors équivalente à une clé DH de 15360 bits. Cependant je ne vous conseille pas d’utiliser P-521 puisqu’il est incompatible avec un très grand nombre de navigateurs, notamment Chrome, ou la compatibilité a été mystérieusement retirée

Notre chère NSA recommande d’utiliser P-384 au maximum, sachant que P-256 n’a pas encore été cassé.

Configurer HTTPS sur Nginx

P-384 fonctionne avec tous les navigateurs et OS compatibles avec TLS 1.2, on ne va donc pas s’en priver :

ssl_ecdh_curve secp384r1;

Pour info, ECDH P-384 équivaut à DH 7680 bits, ce qui est largement suffisant.

Edit : Depuis Nginx 1.11.0, on peut spécifier plusieurs curves :

ssl_ecdh_curve sect571r1:secp521r1:brainpoolP512r1:secp384r1;

Cipher Suite

La suite cryptographique est… bon, on va citer Wikipédia ce sera plus clair pour tout le monde 😀

Une suite cryptographique (cipher suite en anglais) est le nom de la combinaison des algorithmes d’échange de clés, d’authentification, de chiffrement par bloc et génération du code d’authentification de message (MAC) utilisée afin d’établir le paramétrage de sécurité pour une connexion réseau utilisant le protocole de communication Secure Socket Layer (SSL) et Transport Layer Security (TLS).

La Cipher Suite est très importante puisqu’elle va garantir que le client utilisera uniquement des paramètres dans cette liste s’il est compatible.

L’ANSSI recommande d’utiliser AES 128 bits, et la NSA recommande d’utiliser AES 256 bits.

Configurer HTTPS sur Nginx

AES 256 bits ayant plus de potentiel pour une side timing attack, il est préférable de garder une compatibilité avec AES 128 bits. De plus, si vous n’autorisez que AES-256, les navigateurs compatibles avec HTTP/2 ne pourront pas accéder à votre site puisqu’à l’heure actuelle, la négociation ne se fait pas en AES-256.

Voici donc la Cipher Suite que je vous conseille :

ssl_ciphers EECDH+AESGCM:EECDH+CHACHA20:EECDH+AES;

Elle est compatible AES CBC/GCM 128/256 bits, certificat RSA/ECDSA, soit avec quasiment tous les OS et navigateurs qui fonctionnent avec TLS 1.2, et elle priorise AES GCM.

Edit : j’ai jouté CHACHA20. C’est un nouvel algorithme qui est parfois plus rapide parfois plus lent que AES. Mais c’est surtout une alternative qui n’émane pas de la NSA !

On peut ajouter ceci, pour s’assurer que le client utilisera bien nos ciphers en priorité :

ssl_prefer_server_ciphers on;

Par ailleurs vous remarquerez que l’on utilise ECDHE et non pas DHE (le dernier E est pour Exchange)

Online Certificate Status Protocol (OCSP)

OCSP est un protocole qui permet de vérifier si un certificat est valide ou révoqué. Pour cela, à chaque connexion, le client fait une requête à un répondeur OCSP, ce qui peut poser des problèmes de performance et de confidentialité.

C’est pour cela que maintenant, on utilise OCSP Stapling, qui corrige les problèmes de OCSP. En effet c’est le serveur qui fait les vérifications, et une confirmation signée de l’Autorité de Certification est directement donnée dans le TLS handshake, avec un timestamp, soit une durée de validité du message.

Pour cela rien de plus simple (ou pas), il faut d’abord ajouter un fichier contenant le certificat root et le certificat intermédiaire de votre autorité de certification. Évidemment, Le OCSP Stapling ne peut pas être utilisé avec un certificat auto-signé.

Une fois que cela est fait, il faut rajouter cette directive :

ssl_trusted_certificate /chemin/vers/chain.pem;

Cela permettra à Nginx de savoir à quelle autorité de certification il devra causer.

Pour Let’s Encrypt ce sera ceci :

ssl_trusted_certificate /etc/letsencrypt/live/domain.com/chain.pem;

Ensuite, on active OCSP Stapling :

ssl_stapling on;
ssl_stapling_verify on;

Par défaut, Nginx résoudra les noms de domaines des répondeurs OCSP avec les serveurs DNS par défaut du système soit ceux dans /etc/resolv.conf. La plupart des sites recommandent les serveurs DNS publics de Google, mais on a aussi des serveurs DNS en France qui fonctionnent tout aussi bien : ceux du FAI Associatif FDN par exemple.

resolver 80.67.169.12 80.67.169.40 valid=300s;
resolver_timeout 5s;

Pour plus de rapidité et de confidentialité, vous pouvez utiliser un résolveur DNS local, et pourquoi pas le combiner avec un serveur DNS de la FDN pour la redondance :

resolver 127.0.0.1 80.67.169.12 valid=300s;
resolver_timeout 5s;

Vous pouvez vérifier que OCSP est fonctionnel avec la commande suivante :

openssl s_client -connect angristan.fr:443 -tls1_2 -tlsextdebug -status | grep "OCSP Response Status: successful"

Ou sur SSL Labs :

Configurer HTTPS sur Nginx

HTTP Strict Transport Security (HSTS)

HSTS est un header HTTP qui dit à un visiteur de se connecter directement en HTTPS à sa prochaine visite. Cela permet donc d’avoir une communication entièrement chiffrée, et d’éviter la redirection que l’on a vu au début de l’article.

Il suffit d’ajouter un header à Nginx :

add_header Strict-Transport-Security "max-age=15552000; includeSubdomains; preload";

HSTS sera donc valide pendant 15552000 secondes soit pendant 180 jours, il sera aussi valable pour les sous-domaines. Faites donc attention, il faut que tous vos sites sur ce domaine soit en HTTPS (certificat valide uniquement)

Si vous ne voulez activer HSTS que pour un domaine ou sous-domaine (ce que je conseille) :

add_header Strict-Transport-Security "max-age=15552000; preload";

Vous pouvez aller plus loin avec HSTS preload. Si vous avez ajouté le header ci-dessus, vous pouvez inscrire votre domaine sur cette liste. Comme le site l’indique, le domaine de votre site sera hardcodé dans les navigateurs suivant :

  • Chrome
  • Firefox
  • IE 11
  • Edge
  • Safari

Cela signifie que le navigateur n’aura même pas besoin de communiquer avec votre serveur une seule fois pour qu’il sache qu’il doit communiquer avec vous en HTTPS-only. Attention, vous pouvez difficilement vous retirer de la liste, il faudra donc être sûr que votre site restera à tout jamais en HTTPS ! 😉

HSTS preload sera activé au bout de quelques jours. Vous pouvez le vérifier sur SSL Labs :

Configurer HTTPS sur Nginx

Bien entendu, HSTS Preload n’est pas une obligation.

ATTENTION : activer HSTS signifie que votre domaine voire tous vos sous-domaines devront obligatoirement être accessible en HTTPS pour (presque) toujours ! C’est donc lourd de conséquence, ne le fait juste que sur des domaines critiques ou des sites publics qui ont besoin d’êtres performants. 

Cache de session

Ces directives définissent le cache et le temps qu’un client peut garder les paramètres HTTPS en cache :

ssl_session_cache shared:SSL:10m;
ssl_session_timeout 5m;
ssl_session_tickets off;

Ils sont détaillés sur la doc Nginx.

Tester sa configuration

Il existe de très bons outils pour tester sa configuration HTTPS.

Le premier est le très connu SSL Lab de Qualys. Il est très complet, et détaillera tous les aspects de votre configuration : les Ciphers, OCSP, HSTS, HPKP (je n’ai pas parlé de ce dernier dans cet article puisque je ne l’utilise pas). Un de ses principaux avantages est qu’il vous permet aussi de voir avec quels OS et navigateurs votre configuration actuelle est compatible :

Configurer HTTPS sur Nginx

Vous pouvez voir les protocoles et Ciphers Suites disponibles :

Configurer HTTPS sur Nginx

Et bien sûr, notre super note ! 😀

Configurer HTTPS sur Nginx

Un autre super outil est CryptCheck fait par le fameux « crypto-terroriste individuel auto-radicalisé sur l’Internet digital » qu’est @Aeris22.

Il est aussi super complet :

Configurer HTTPS sur Nginx

PS : il est bien possible d’avoir 100% partout avec une cipher suite AES 256 bits only, mais elle n’est pas compatible HTTP/2.

Configurer HTTPS sur Nginx

Enfin, il y a SSL  Decoder qui vous donnera tout un tas d’informations. Il ne vous donne pas de note mais est très complet en terme d’analyse. À utiliser pour les utilisateurs confirmés 😉

Sources et ressources

@Aeris22, alias Imirhil, est un pro en sécurité qui parle très souvent de chiffrement. Je vous conseille de regarder sa conférence SSL/TLS pour les nuls, et de lire ses articles sur CryptCheck ou encore Let’s Encrypt.

L’article étant un peu (très) long, voici un résumé de ma configuration HTTPS:

server {
 listen 80;
 server_name domain.com;
 return 301 https://$server_name$request_uri;
}
server {
 listen 443 ssl http2; #Nginx > 1.9.5
 listen 443 ssl spdy; #Nginx < 1.9.5
 server_name domain.com;
 
 [....]
 # Le reste de votre conf
 [....]

 ## Certificates
 ssl_certificate /etc/nginx/ssl/domain/cert.pem;
 ssl_certificate_key /etc/nginx/ssl/domain/key.pem;
 ssl_trusted_certificate /chemin/vers/chain.pem;

 ## Protocol
 ssl_protocols TLSv1.2;

 ## Diffie-Hellman
 ssl_ecdh_curve secp384r1;

 ## Ciphers
 ssl_ciphers EECDH+CHACHA20:EECDH+AESGCM:EECDH+AES;
 ssl_prefer_server_ciphers on;

 # OCSP Stapling
 resolver 80.67.169.12 80.67.169.40 valid=300s;
 resolver_timeout 5s;
 ssl_stapling on;
 ssl_stapling_verify on;

 ## TLS parameters
 ssl_session_cache shared:SSL:10m;
 ssl_session_timeout 5m;
 ssl_session_tickets off;

 ## HSTS
 add_header Strict-Transport-Security "max-age=15552000; includeSubdomains; preload";
}

N’hésitez pas à tester les configurations des sites que vous visitez (leur cadenas vert n’est peut-être pas si vert que ça), et partagez vos jolis A+ pour qu’on ait un web plus sécurisé !

Je remercie particulièrement @HLFH_Space qui m’a énormément aidé et qui est (presque) une bible en la matière. 😉

Sources :


Dernière modification le 28 mars 2022.
S’abonner
Notification pour
guest

43 Commentaires
Le plus récent
Le plus ancien Le plus populaire
Commentaires en ligne
Afficher tous les commentaires
Thomas Texier

Bonjour. Merci pour cet article.
pour info, il manque un point virgule à la fin de cette commande:

ssl_protocols TLSv1.2 TLSv1.1 TLSv1
Aelisya

Bonjour Angristan,

Je te conseille de modifier ce tuto et ajouter a la cipher suite de
ssl_ciphers EECDH+AESGCM:EECDH+CHACHA20:EECDH+AES;
a
ssl_ciphers EECDH+AESGCM:EECDH+CHACHA20:EECDH+AES!AES128;

Cela permet d’avoir un support complet (de toutes les handshake simulation) et également une CipherStrengt a 100

guillaume

Bravo pour ce tuto, un des premiers qui soit parfaitement clair et instructif, mon site a démarré du premier coup en Https. j’en revient toujours pas. bravo. on devrait bruler un cierge pour tous ceux qui postent des tutos aussi détaillés et qui fonctionnent.

LJB

Bonjour Angristan,

Article détaillé de grande qualité et fort intéressant, bravo !

J’ai testé avec plaisir le script de compilation nginx avec LibreSSL.
Après quelques ajustement NGINX fonctionne parfaitement sous Debian 8 Jessie.

Je me permets qques remarques :
Les versions de NGINX, PageSpeed, LibreSSL, OpenSSL sont codées en dur.
Ne serait il pas possible de récupérer la référence de la dernière version automatiquement et de l’affecter à ces différentes variables ?
Pour les habitués (et un peu fainéants aussi ;0) peut être rajouter les Répertoires
sites-available et sites-enable ainsi que de rajouter les includes qui vont bien pour ne pas galérer avec le debbug

Merci pour cet excellent travail !

Bien cordialement.

Qwaser

Merci à toi pour ce tutoriel, il m’a beaucoup aider pour augmenter la configuration HTTPS de mes sites. Cependant après être passé à Nginx 1.11.3, j’ai souhaitez mettre cette ligne : « ssl_ecdh_curve sect571r1:secp521r1:brainpoolP512r1:secp384r1; » or Nginx me sors l’erreur suivante ensuite : « nginx: [emerg] OBJ_sn2nid(« sect571r1:secp521r1:brainpoolP512r1:secp384r1″) failed: unknown curve (SSL:) »
Serais-tu d’où cela peut provenir ?

Merci d’avance.

jey

j’ai cette erreur pour le preload >> Warning: Unnecessary HSTS header over HTTP
t’as une idée?
sinon nikel , j’ai bookmarqué ton article d’ailleur ;-p

jey

Sur le site hhstspreload

Qwaser

J’ai eu cette erreur à l’instant en souhaitant ajouter mon site également à la liste. Tu as dû simplement mettre la ligne ‘add_header Strict-Transport-Security « max-age=15552000; includeSubdomains; preload »;’ dans un block correspondant au port 80, soit HTTP. Or cette ligne n’a pas d’utilité dans un block HTTP, seulement dans un block HTTPS 😉

En espérant que ton erreur est bien la même que la mienne 🙂

jey

Non malheureusement ce n’est pas ça je pense plutôt à une merdouille niveau dns .
J’ai un cname pour les sous dom du style :
*.ndd.com CNAME ndd.com.

Est ce possible que ça vienne de là?

J’ai aussi pour ngnix l’option name_server ndd.com http://www.ndd.com;

Peut être ça la cause?

jey

ha j’avais répondu mais ma réponse a disparue 😉
non ce n’est pas ce soucis ce serait trop simple lol.
je pense plutôt a un soucis dns mais bon je zappe cette partie c’est pas grave merci.

Nilav

Merci pour ce tuto,

Il m’a permis d’obtenir le saint A+. En revanche, je suis sans ALPN n’ayant pas spécialement envie de m’amuser à compiler nginx avec openssl 1.0.2. Je vais gentiment attendre que cela finisse en mainline, sauf s’il reprenait à Google la folle idée de le rendre obligatoire alors que tout ça n’est qu’en bêta…

D’ailleurs, la note de http://www.google.fr n’est pas jojo, ils ont clairement fait le choix de l’accessibilité à la sécurité (en même temps, ils doivent aussi avoir ce qu’il faut pour se défendre des attaques en SSL/TLS1). Etant donné ma cible, un TLS1.2 uniquement ne me posera pas de soucis.

Nilav

Ah je vais regarder pour LibreSSL

Pour Google, au niveau de Chrome, ils veulent activer le HTTP2 uniquement avec ALPN (plus de support de NPN). D’ailleurs, c’est toujours le cas, ca a juste été repoussé à mai. Demain quoi.
http://blog.chromium.org/2016/02/transitioning-from-spdy-to-http2.html
https://ma.ttias.be/chrome-drops-npn-support-for-http2-alpn-only/

Novakin

ssl_ciphers ECDHE+AESGCM256:ECDHE+AES256; ne fonctionne pas sous nginx 1.9.5 🙁

Novakin

Euh pardon, je me suis complètement plante.

ssl_ciphers ECDHE+AESGCM:EECDH+AES; bug sous 1.9.12 avec le « vrai » http2 et pas le mod spdy

Novakin

ERR_SPDY_INADEQUATE_TRANSPORT_SECURITY en erreur du serveur

Nova

Oui je m’étais plante dans mon premier commentaire. J’ai corrigé dans le second. Je suis bien en 1.9.12.

Je vais regardé comment je peux paramétrer au mieux http2 et je te ferai un retour.

wxcv

Hey,
J’avais jamais entendu parler de « ssl_ecdh_curve secp384r1; » avant.
Merci beaucoup 🙂

Yax

Sacré article, très technique et très bien expliqué ! J’ai récemment profité de la sortie de Let’s Encrypt pour renforcer ma configuration HTTPS avec NginX et pour cela je me suis reposé sur le générateur de Mozilla (https://mozilla.github.io/server-side-tls/ssl-config-generator) qui permet d’avoir une idée assez précise à travers ses modes (old, intermediate, modern) des navigateurs supportés car il y a effectivement un compromis à trouver entre une sécurité au top et les navigateurs supportés par ta configuration pour ne pas perdre trop de lecteurs. Ton article m’a permis de mieux comprendre la configuration que j’ai mis en place.

Olivier

Merci pour ce excellent article, je le garde moi aussi en mémo. Pourquoi tu as choisi les recommandations de la NSA plutôt que celle de l’ANSSI ?

jujuju

Super ton certificat de la mort qui tue.
Sauf qu’il n’est même pas compatible avec les « très vieux » devices, genre mon blackberry curve 9320 sorti en … 2012 !
Finalement on est tous un peu responsable de l’obsolescence programmée.

jujuju

Comment savoir avant d’acheter un appareil qu’il ne sera pas mis à jour ? 😀
et pourquoi ne pas autoriser le http non sécurisé ?

ignace72

Merci à toi, super article qui m’a permit d’augmenter encore mes scores.
J’ai comme toi au deux tests.
Merci

ignace72

Bon, je suis passé à la cipher suite de la mort qui pue que tu as donné et j’ai toujours des visites de navigateurs et d’OS différents. mes stats n’ont pas baissé.
Il me manque plus qu’une version stable de Nginx supportant http2.
Encore merci pour ton travail, ça fait plaisir, un jeune qui intéresse à autre chose que son ordiphone, FB et compagnie. Bravo.

ignace72

Oui, je parle de celle-là, bon, j’ai lu la partie édité et je suis repassé à la cipher conseillé.
Si je suis bien, c’est un peut jeune pour le AES-256 exclusif.

Pour Nginx, j’ai bien vue la mainline mais la stable est la version 1.8.0 et je préfère être en stable. Autant ça ne me gène pas de faire joujou avec les configurations des logiciels, autant je préfère avoir des versions stables, les dernières versions, mais stables. En tout cas j’ai déjà OpenSSL 1.0.2 donc je suis près pour Nginx 2.0.0 (j’imagine que ça sera la prochaine version stable).

Merci pour ces explications, j’apprends plein de trucs.

Mathias

Hello Stanislas,

Au top ton article, il me fait un excellent mémo.
Merci !