infra / nginx
Headers de sécurité
Explication
Ce que vous allez apprendre
- Ajouter les headers de sécurité essentiels : HSTS, X-Frame-Options, X-Content-Type-Options
- Comprendre pourquoi
add_header ... always;est nécessaire pour les réponses d'erreur - Écrire une Content-Security-Policy (CSP) de base et comprendre son risque principal
- Masquer la version de Nginx exposée par défaut avec
server_tokens off - Bloquer l'accès aux fichiers sensibles souvent oubliés en production (
.git,.env)
Dans quel contexte ?
Un audit de sécurité externe pointe qu'un site en production ne renvoie aucun header de sécurité HTTP : aucune protection contre le clickjacking (afficher le site dans une iframe malveillante pour piéger un clic), aucune protection contre le sniffing MIME, et la version exacte de Nginx est visible dans chaque réponse, facilitant la recherche de vulnérabilités connues par un attaquant.
D'abord, une poignée de headers forment le socle minimal
HSTS force le navigateur à toujours utiliser HTTPS pour ce domaine, même si un lien http:// est tapé à la main ou cliqué depuis un vieux favori. X-Frame-Options empêche l'affichage du site dans une <iframe> d'un autre domaine, une protection directe contre le clickjacking. X-Content-Type-Options empêche le navigateur de "deviner" un type de fichier différent de celui déclaré par le serveur, ce qui limite certaines classes d'attaques XSS.
Une fois ces headers ajoutés, un détail syntaxique compte énormément
Sans le mot-clé always à la fin de la directive add_header, le header n'est envoyé QUE sur les réponses de succès (2xx, 3xx) — pas sur les réponses d'erreur (4xx, 5xx). Or, une page d'erreur reste une cible potentielle pour du clickjacking ou du sniffing MIME : always garantit que la protection s'applique dans tous les cas.
| Header | Protège contre | Nécessite always |
|---|---|---|
Strict-Transport-Security | Downgrade HTTP après un lien tapé en clair | Oui |
X-Frame-Options | Clickjacking (iframe malveillante) | Oui |
X-Content-Type-Options | Sniffing MIME | Oui |
Content-Security-Policy | XSS (scripts injectés) | Oui |
Ensuite, le header le plus puissant est aussi le plus délicat à régler
La Content-Security-Policy (CSP) restreint précisément quelles sources de scripts, styles et images le navigateur a le droit de charger. C'est la protection la plus efficace contre le XSS, mais une règle trop stricte casse silencieusement des fonctionnalités du site : aucune erreur n'apparaît dans les logs Nginx, tout se passe dans la console du navigateur, invisible sans inspection manuelle.
Piège fréquent
Déployer directement une CSP stricte en production, sans phase de test, risque de casser des scripts tiers légitimes (widgets de paiement, analytics) sans que personne ne s'en aperçoive avant que des utilisateurs ne signalent des dysfonctionnements. Teste toujours d'abord en mode Content-Security-Policy-Report-Only, qui journalise les violations sans bloquer réellement le contenu.
Prérequis
Cette leçon suppose une compréhension de base des attaques XSS et clickjacking : sans ce contexte, ces headers peuvent sembler être une checklist arbitraire plutôt que des protections ciblées contre des menaces précises.
Il reste deux dernières mesures simples mais efficaces
server_tokens off; masque la version exacte de Nginx dans les réponses, réduisant l'information disponible pour un attaquant en reconnaissance. Bloquer explicitement l'accès aux fichiers sensibles souvent oubliés — .git, .env, fichiers .bak ou .sql — avec un return 404 (plutôt qu'un 403, qui révèle que le fichier existe bel et bien) referme des portes d'entrée classiques.
Bonne pratique
Vérifie régulièrement les headers effectivement renvoyés par ton site avec curl -sI : une configuration correcte au moment de sa création peut se perdre après une modification ultérieure d'un server block, sans que personne ne le remarque avant un audit de sécurité.
Maintenant que la posture de sécurité HTTP est solide, la prochaine leçon s'intéresse à un aspect opérationnel tout aussi essentiel : les logs, leur format et leur exploitation pour diagnostiquer un problème en production.
Commandes & code
Headers de sécurité
server {
listen 443 ssl;
server_name example.com;
# HSTS : force le navigateur à toujours utiliser HTTPS pour ce domaine, même sur un lien http:// tapé à la main
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
# Empêche l'affichage du site dans une <iframe> d'un autre domaine (protection clickjacking)
add_header X-Frame-Options "SAMEORIGIN" always;
# Empêche le navigateur de "deviner" un type MIME différent de celui déclaré (protection contre certains XSS)
add_header X-Content-Type-Options "nosniff" always;
# Contrôle les infos envoyées dans le header Referer lors d'une navigation sortante
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Désactive des API navigateur sensibles par défaut (caméra, micro, géoloc) sauf besoin explicite
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
}# Content-Security-Policy : la protection la plus puissante contre le XSS, aussi la plus délicate à régler
server {
add_header Content-Security-Policy "
default-src 'self';
script-src 'self' https://cdn.example.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
connect-src 'self' https://api.example.com;
frame-ancestors 'self';
base-uri 'self';
form-action 'self';
" always;
# ATTENTION : une CSP trop stricte casse le site en silence (rien dans les logs Nginx, tout dans la console navigateur)
}# Masquer la version de Nginx exposée par défaut dans les headers et pages d'erreur
http {
server_tokens off; # remplace "Server: nginx/1.24.0" par juste "Server: nginx"
}# Bloquer l'accès aux fichiers sensibles souvent oubliés en prod
server {
location ~ /\.(git|env|htaccess) {
deny all;
return 404; # 404 plutôt que 403 : ne révèle même pas que le fichier existe
}
location ~* \.(bak|sql|log|conf)$ {
deny all;
return 404;
}
}# Vérifier les headers effectivement renvoyés
curl -sI https://example.com | grep -Ei "strict-transport|x-frame|x-content-type|content-security|referrer-policy"Résumé
alwayssuradd_headerest nécessaire pour que le header soit envoyé même sur les réponses d'erreur (4xx/5xx).- HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy : le socle minimal à mettre partout.
- CSP est le plus protecteur contre le XSS mais casse silencieusement le site si mal configuré : tester en mode
Content-Security-Policy-Report-Onlyd'abord. server_tokens off+ blocage des fichiers sensibles (.git,.env,.bak) réduisent la surface de reconnaissance d'un attaquant.
Exercices pratiques
Mission : corriger les manques révélés par un audit de sécurité HTTP
Objectif : Ajouter les headers de sécurité essentiels avec la portée correcte et fermer les fichiers sensibles exposés par erreur.
Contexte
Un audit externe constate trois manques sur example.com : aucun header de sécurité HTTP n'est renvoyé (même pas sur les pages d'erreur 4xx), la version exacte de Nginx apparaît dans chaque réponse, et .git/config est accessible publiquement via l'URL.