Pourquoi les headers de sécurité comptent toujours en 2026
La plupart des sites compromis ne tombent pas à cause d'une faille zero-day. Ils tombent à cause de choses banales : un script injecté, une page chargée dans une iframe malveillante, un navigateur qui devine un type de fichier qu'il n'aurait pas dû deviner. Les headers HTTP de sécurité sont la défense la moins chère que tu déploieras jamais — quelques lignes de config serveur qui disent au navigateur exactement ce que ton site a le droit de faire.
Le problème ? Les études sur le top million de sites montrent régulièrement que moins de la moitié envoient une Content-Security-Policy, et beaucoup de celles qui existent sont si permissives qu'elles ne servent à rien. On va corriger ça.
Les headers essentiels, et ce que chacun bloque
Chaque header ci-dessous répond à une classe d'attaque précise. Si tu ne retiens qu'une chose, retiens ce tableau :
| Header | Bloque | Valeur recommandée |
|---|---|---|
Content-Security-Policy | XSS, scripts injectés, exfiltration de données | Spécifique au site (voir plus bas) |
Strict-Transport-Security | Downgrade HTTPS, SSL stripping | max-age=31536000; includeSubDomains; preload |
X-Content-Type-Options | Attaques par MIME sniffing | nosniff |
X-Frame-Options | Clickjacking (anciens navigateurs) | DENY ou SAMEORIGIN |
Referrer-Policy | Fuite d'URL vers des tiers | strict-origin-when-cross-origin |
Permissions-Policy | Abus silencieux de la caméra, du micro, de la géoloc | camera=(), microphone=(), geolocation=() |
Quelques précisions sur ceux qui posent le plus de questions :
Strict-Transport-Security (HSTS)
HSTS dit au navigateur : ne parle plus jamais à ce site en HTTP non chiffré. Sans lui, un utilisateur qui tape tonsite.com fait d'abord une requête en clair — et sur un Wi-Fi hostile, cette unique requête suffit pour une attaque de SSL stripping. Commence avec un max-age court (300 secondes) pendant tes tests, puis monte à un an. N'ajoute preload que quand tu es certain que tous tes sous-domaines servent du HTTPS — le preload est très difficile à annuler. Et évidemment, HSTS ne sert à rien si ton certificat est cassé : vérifie-le d'abord avec un SSL Checker.
X-Frame-Options vs frame-ancestors
Ces deux-là se recoupent, et ça embrouille tout le monde. X-Frame-Options: DENY est le header historique qui empêche ta page d'être mise en iframe. Son remplaçant moderne est la directive CSP frame-ancestors 'none', plus flexible (elle accepte une liste d'origines autorisées). Quand les deux sont présents, les navigateurs qui supportent CSP ignorent X-Frame-Options. La bonne pratique en 2026 : envoyer les deux — frame-ancestors pour les navigateurs modernes, X-Frame-Options en filet de sécurité pour les anciens.
X-Content-Type-Options
Une seule valeur possible : nosniff. Elle empêche le navigateur de "sniffer" le contenu et d'exécuter un fichier comme du JavaScript parce qu'il ressemble à du JavaScript, alors que ton serveur avait annoncé du texte brut. Une ligne qui ferme toute une classe d'attaques. Il n'y a aucune raison de ne pas l'envoyer.
Content-Security-Policy : plongée en profondeur
La CSP, c'est le poids lourd. C'est une liste blanche de tout ce que ta page a le droit de charger — scripts, styles, images, polices, frames, connexions. Un bon point de départ ressemble à ça :
Content-Security-Policy:
default-src 'self';
script-src 'self' https://cdn.example.com;
style-src 'self';
img-src 'self' data: https:;
font-src 'self';
connect-src 'self' https://api.example.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self';
Les directives à bien comprendre :
default-src— la valeur de repli pour tout ce que tu ne précises pas. Mets-la toujours à'self'ou'none'.script-src— la plus importante. C'est ton bouclier anti-XSS.base-urietform-action— souvent oubliées, elles empêchent un attaquant de rediriger tes formulaires ou de réécrire tes URLs relatives.frame-ancestors— la protection anti-clickjacking vue plus haut.
Nonces vs unsafe-inline
La pire chose que tu puisses mettre dans une CSP, c'est script-src 'unsafe-inline'. Ça rouvre exactement la porte que la CSP est censée fermer : n'importe quel script injecté dans ton HTML s'exécute. Si tu as des scripts inline que tu ne peux pas déplacer dans des fichiers, utilise des nonces :
<!-- Le serveur génère un nonce aléatoire à chaque réponse -->
<script nonce="r4nd0mB4se64">
initApp();
</script>
Content-Security-Policy: script-src 'nonce-r4nd0mB4se64' 'strict-dynamic';
Le nonce doit être imprévisible et unique par requête — un attaquant capable de le deviner contourne toute la politique. Associe-le à 'strict-dynamic' : les scripts chargés par tes scripts de confiance seront autorisés eux aussi, ce qui rend les bundlers modernes et les tag managers beaucoup moins pénibles.
Report-Only : déployer sans rien casser en prod
Une CSP stricte déployée à l'aveugle va forcément casser quelque chose — un snippet d'analytics, une iframe de paiement, une police oubliée. C'est exactement le rôle de Content-Security-Policy-Report-Only. Même syntaxe, mais les violations sont signalées, jamais bloquées :
Content-Security-Policy-Report-Only:
default-src 'self';
report-uri https://tonsite.com/csp-reports;
Laisse tourner le mode report-only une semaine ou deux, analyse les violations, ajoute à la liste blanche ce qui est légitime, puis passe en mode strict. Pour construire la politique elle-même, c'est beaucoup plus simple avec un Générateur de CSP — tu choisis tes sources directive par directive et tu copies le résultat, au lieu d'assembler les chaînes à la main.
Snippets de config Nginx et Apache
Nginx — dans ton bloc server :
add_header Content-Security-Policy "default-src 'self'; frame-ancestors 'none'; base-uri 'self'" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
Le flag always est crucial : sans lui, Nginx n'envoie pas tes headers sur les réponses d'erreur (404, 500), et ces pages-là sont tout aussi attaquables.
Apache — dans ton vhost ou .htaccess, avec mod_headers activé :
Header always set Content-Security-Policy "default-src 'self'; frame-ancestors 'none'; base-uri 'self'"
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "DENY"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
Comment auditer tes headers actuels
Avant d'ajouter quoi que ce soit, fais l'état des lieux. Trois étapes rapides :
- Scanne ta posture de sécurité. Passe ton domaine dans un Security Headers Checker. Tu obtiens un verdict header par header : ce qui est présent, ce qui manque, ce qui est mal configuré.
- Inspecte la réponse brute. Un HTTP Headers Checker te montre tous les headers que ton serveur envoie réellement — pratique pour repérer les doublons (deux CSP = c'est l'intersection qui s'applique, et ça surprend) ou les headers injectés par un CDN que tu avais oublié.
- Vérifie ta fondation TLS. HSTS et les cookies sécurisés supposent un HTTPS en bonne santé — contrôle l'expiration, la chaîne et les protocoles avec le SSL checker.
Relance le scan après chaque déploiement qui touche ton reverse proxy. Les headers régressent en silence : une migration de CDN ou un nouveau load balancer peut tout effacer sans aucun symptôme visible.
Les erreurs classiques à éviter
- Mettre une CSP mais garder
unsafe-inlineetunsafe-eval— tu as construit une clôture en laissant le portail ouvert. - HSTS
preloaddès le premier jour — passe d'abord tout en HTTPS ; sortir de la liste preload prend des mois. - Des headers uniquement sur la page d'accueil — un routing mal configuré laisse souvent les routes API ou les pages d'erreur sans protection.
- Les headers obsolètes —
X-XSS-Protectionest déprécié et peut même introduire des failles sur de vieux navigateurs ; mets-le à0ou supprime-le.
Vérifie ton site en 30 secondes
Tu sais maintenant à quoi sert chaque header et à quoi ressemble une bonne valeur. La suite prend trente secondes : colle ton URL dans le Security Headers Checker et vois exactement quelles protections te manquent. Gratuit, instantané, sans compte — puis utilise le Générateur de CSP pour construire la politique qui comble les trous.