Les en-têtes de sécurité HTTP sont l'une des protections les moins coûteuses à mettre en place : quelques lignes de configuration suffisent à bloquer des classes entières d'attaques côté navigateur (clickjacking, injection de scripts, interception sur HTTP). Ce tutoriel montre comment les déclarer dans nginx, et surtout comment éviter le piège qui fait silencieusement disparaître la moitié d'entre eux.
Les en-têtes à connaître
| En-tête | Protège contre | Valeur de départ raisonnable |
|---|---|---|
Strict-Transport-Security |
Rétrogradation vers HTTP, interception | max-age=31536000; includeSubDomains |
Content-Security-Policy |
Injection de scripts (XSS), chargements non maîtrisés | default-src 'self' puis à affiner |
X-Frame-Options |
Clickjacking (site affiché dans une iframe) | SAMEORIGIN |
X-Content-Type-Options |
Interprétation d'un fichier avec un mauvais type | nosniff |
Referrer-Policy |
Fuite d'URL internes vers des sites tiers | strict-origin-when-cross-origin |
Permissions-Policy |
Accès abusif caméra, micro, géolocalisation… | camera=(), microphone=(), geolocation=() |
Le piège : add_header ne s'hérite pas toujours
Dans nginx, une directive add_header déclarée au niveau server est héritée par les blocs location… sauf si la location déclare elle-même au moins un add_header. Dans ce cas, tous les en-têtes du niveau supérieur sont ignorés pour cette location.
server {
add_header X-Frame-Options "SAMEORIGIN" always;
location /assets/ {
# Cette ligne fait disparaître X-Frame-Options pour /assets/ !
add_header Cache-Control "public, max-age=31536000" always;
}
}C'est l'erreur la plus fréquente : la configuration semble correcte, mais certaines URL sont servies sans protection.
La solution : un fichier inclus dans chaque location
Regroupez les en-têtes dans un fichier dédié, par exemple /etc/nginx/snippets/security-headers.conf :
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header Content-Security-Policy "default-src 'self'; img-src 'self' data:; object-src 'none'; frame-ancestors 'self'; base-uri 'self'" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;Puis incluez-le dans chaque location qui sert du contenu :
location / {
include /etc/nginx/snippets/security-headers.conf;
try_files $uri $uri.html $uri/index.html =404;
}
location /assets/ {
include /etc/nginx/snippets/security-headers.conf;
add_header Cache-Control "public, max-age=31536000, immutable" always;
}Le paramètre always garantit que les en-têtes sont aussi envoyés sur les réponses d'erreur (404, 500…), qui sont souvent oubliées.
Vérifier le résultat
Testez plusieurs types d'URL, pas seulement la page d'accueil :
for path in / /assets/app.css /page-inexistante; do
echo "== $path"
curl -sI "https://votre-domaine.fr$path" | grep -iE 'strict-transport|content-security|x-frame|x-content-type|referrer|permissions'
doneChaque URL doit afficher les six en-têtes. Si une seule en manque, cherchez un add_header isolé dans la location correspondante.
Points d'attention
- HSTS est difficile à annuler : une fois reçu, le navigateur refusera toute connexion non HTTPS au domaine pendant toute la durée de
max-age. Commencez par une valeur courte (max-age=300) le temps de valider que tout le site fonctionne en HTTPS, sous-domaines compris si vous utilisezincludeSubDomains. - La CSP se construit progressivement : une politique trop stricte casse le site (scripts, polices, outils d'analyse). Utilisez d'abord
Content-Security-Policy-Report-Onlypour observer les violations dans la console du navigateur sans rien bloquer, puis basculez en mode bloquant. - Derrière un reverse proxy (Traefik, load balancer…), vérifiez que les en-têtes ne sont pas définis deux fois avec des valeurs différentes : c'est la valeur la plus restrictive ou la plus inattendue qui risque de s'appliquer selon le navigateur.
Vous souhaitez un audit de la configuration de vos serveurs web ? Contactez-nous.