sMug@replicatorbe
~/Publications/Infrastructure/durcir-nginx-sans-casser-le-tls

Durcir nginx sans casser le TLS

Infrastructure / /2 min de lecture

Une configuration TLS stricte qui obtient un A+ sans exclure les clients réels — et la méthode pour vérifier que rien n'est cassé avant de recharger.

Durcir un reverse proxy est facile ; le durcir sans casser de client demande de savoir ce qu'on retire. Voici la configuration que j'applique par défaut, et surtout la vérification qui va avec.

Le socle

Trois directives font l'essentiel du travail :

ssl_protocols       TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_ciphers         ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305;

Laisser ssl_prefer_server_ciphers off est contre-intuitif : en TLS 1.3, le client choisit mieux que nous, parce qu'il sait sur quel matériel il tourne.

Ce qu'on retire, et ce que ça coûte

RetiréCasseVerdict
TLS 1.0 / 1.1Android < 5, IE sur XPà retirer
Suites CBCClients Java 7 anciensselon le parc
ssl_session_ticketsrien de visibleà retirer

Règle que je m'impose : on ne retire une suite qu'après avoir regardé les logs d'accès réels, pas la théorie.

Vérifier avant de recharger

Dans l'ordre, jamais l'inverse :

  1. nginx -t — la syntaxe seulement
  2. le handshake, depuis l'extérieur :
    • openssl s_client -connect exemple.be:443 -tls1_2
    • testssl.sh --severity HIGH exemple.be
  3. nginx -s reload — rechargement sans coupure

L'erreur classique est d'inverser 2 et 3 : on découvre la casse après l'avoir mise en production.

HSTS, en dernier

Strict-Transport-Security est la seule directive de cette liste qui soit difficile à annuler : une fois l'en-tête servi avec un max-age long, les navigateurs refusent le HTTP pendant toute cette durée. Je commence toujours à max-age=300, je laisse tourner une semaine, puis je monte.

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

Le always compte : sans lui, l'en-tête disparaît sur les réponses d'erreur.