Chaque réponse de votre site transporte des en-têtes que le visiteur ne voit jamais. Certains sont des consignes de sécurité pour le navigateur : ne charger des scripts que depuis tel endroit, utiliser HTTPS pour cet hôte, interdire aux autres sites d’intégrer la page dans un cadre, tenir ce cookie hors de portée de JavaScript. Quand ils manquent, le navigateur s’en tient à ses réglages par défaut, plus permissifs. Quand ils sont mal réglés, la connexion au compte ou le paiement peuvent cesser de fonctionner.
Ce guide montre comment lire les en-têtes que votre site envoie réellement, à quoi sert chacun et quelles valeurs choisir pour commencer. Il fournit une configuration de base pour nginx, pour Apache via le fichier .htaccess des hébergements mutualisés et pour des hébergeurs statiques comme Cloudflare Pages et Netlify, signale les positions de l’ANSSI quand elle en a pris, et passe en revue les erreurs qui laissent certaines réponses sans protection. Tous les exemples utilisent example.com.
Portée de ce guide
Le snapshot gratuit lit les en-têtes d’une seule réponse : la page d’accueil de l’origine saisie, après au plus cinq redirections. Il vérifie surtout la présence de chaque en-tête, pas l’adéquation des valeurs à votre site, et ce n’est pas un test d’intrusion.
1. Vérifier vos en-têtes vous-même : DevTools et curl
Dans Chrome ou Edge, ouvrez les outils de développement, sélectionnez le panneau Réseau (Network) et rechargez la page. Cliquez sur la première requête (le document HTML), ouvrez l’onglet En-têtes (Headers) et descendez jusqu’aux en-têtes de réponse (Response Headers). Cochez Conserver le journal (Preserve log) pour garder les requêtes d’un chargement à l’autre et à travers les redirections, et Désactiver le cache (Disable cache) pour obtenir une réponse fraîche plutôt qu’une copie en cache (référence du panneau Network de Chrome DevTools). Le moniteur réseau de Firefox fonctionne de la même façon.
Dans un terminal, curl affiche exactement ce que le serveur envoie :
curl -sS -D - -o /dev/null https://example.com/Ajoutez -L pour suivre les redirections et voir les en-têtes de chaque étape. Sous Windows, appelez curl.exe et remplacez /dev/null par NUL. curl -I est plus court, mais il envoie une requête HEAD au lieu de GET, et certaines applications traitent HEAD par un autre chemin de code : confirmez ce que vous trouvez avec un GET.
Refaites le contrôle sur l’adresse en http:// (elle doit répondre par une redirection 301 ou 308 vers HTTPS), sur l’autre nom d’hôte (avec ou sans www), sur une page qui n’existe pas, une page de connexion, une réponse d’API et un fichier statique. L’application, le serveur web et le CDN posent souvent des en-têtes différents sur chacune de ces réponses, et seul ce qui arrive au navigateur compte.
2. Le rôle de chaque en-tête et une valeur sûre pour commencer
| En-tête | Rôle | Valeur de départ sûre |
|---|---|---|
| Content-Security-Policy | Limite les origines d’où peuvent venir scripts, styles, cadres et autres ressources | Une politique provisoire, envoyée d’abord en Content-Security-Policy-Report-Only |
| CSP frame-ancestors | Désigne les sites autorisés à intégrer la page dans un cadre (protection contre le détournement de clic, ou clickjacking) | frame-ancestors 'self' ou 'none' |
| X-Frame-Options | Ancien contrôle de l’intégration, gardé en repli pour les anciens navigateurs | SAMEORIGIN ou DENY, en cohérence avec frame-ancestors |
| Strict-Transport-Security | Impose HTTPS pour cet hôte pendant max-age secondes | max-age=300, relevé par paliers |
| X-Content-Type-Options | Empêche le navigateur de deviner le type MIME ; bloque les scripts et feuilles de style servis avec un mauvais type | nosniff |
| Referrer-Policy | Règle la part de l’URL de la page transmise aux autres sites dans l’en-tête Referer | strict-origin-when-cross-origin |
| Permissions-Policy | Désactive des fonctions du navigateur, comme la caméra, pour la page et ses cadres | camera=(), microphone=(), geolocation=() |
| Cross-Origin-Opener-Policy | Isole votre fenêtre des pop-ups d’autres origines et de la page qui l’a ouverte | same-origin, ou same-origin-allow-popups pour les pop-ups OAuth ou de paiement |
| Attributs de Set-Cookie | Limitent la circulation des cookies de session et qui peut les lire | Secure; HttpOnly; SameSite=Lax |
| X-XSS-Protection | Pilotait un filtre des anciens navigateurs ; désormais obsolète | À supprimer, ou 0 |
Avec nosniff, le navigateur se fie au Content-Type déclaré et bloque les scripts et feuilles de style qui arrivent avec un autre type : vérifiez ces types avant de l’activer. Sans en-tête Referrer-Policy, les navigateurs actuels appliquent déjà strict-origin-when-cross-origin ; l’OWASP conseille malgré tout de l’envoyer explicitement pour les navigateurs plus anciens, et no-referrer est plus strict si rien de ce dont vous dépendez n’a besoin du référent. Dans Permissions-Policy, () désactive une fonction dans la page et dans chaque cadre qu’elle contient ; n’autorisez une fonction que pour l’origine du widget qui en a besoin. COOP same-origin aide à contrer les attaques par fuite entre origines (XS-Leaks), mais peut casser les pop-ups de connexion ou de paiement servies depuis une autre origine.
3. Content-Security-Policy et frame-ancestors
La CSP indique au navigateur d’où une page peut charger scripts, styles, images, cadres et connexions. Elle limite ce qu’un script injecté peut faire ; elle ne remplace ni l’échappement ni la validation des entrées. Le guide CSP de MDN recommande une CSP stricte, fondée sur un nonce renouvelé à chaque réponse ou sur des empreintes (hashes), plutôt qu’une longue liste d’hôtes autorisés. 'unsafe-inline' en annule une bonne partie de l’intérêt, et le navigateur l’ignore dans toute directive qui contient aussi un nonce ou une empreinte. Ce qui rend une politique stricte difficile, ce sont le plus souvent les codes tiers qui chargent d’autres scripts, comme les gestionnaires de balises (tag managers) et les widgets de chat : notez la raison de chaque exception que vous ajoutez.
default-src sert de valeur de repli aux directives de chargement comme script-src, mais pas à frame-ancestors : une politique default-src 'none' laisse n’importe quel site intégrer la page. Fixez explicitement frame-ancestors 'self', ou 'none', l’équivalent approximatif de X-Frame-Options: DENY (MDN). La fiche OWASP sur les en-têtes HTTP indique que frame-ancestors rend X-Frame-Options obsolète dans les navigateurs qui le prennent en charge, X-Frame-Options couvrant encore les plus anciens ; si vous envoyez les deux, veillez à ce qu’ils autorisent la même chose. L’ANSSI va dans le même sens : ses recommandations pour la mise en œuvre d’un site web préconisent frame-ancestors contre le détournement de clic et qualifient X-Frame-Options d’en-tête non standard, rendu obsolète par CSP. Deux pièges : frame-ancestors, une politique en mode rapport et X-Frame-Options n’ont aucun effet dans une balise <meta>, et X-Frame-Options: ALLOW-FROM fait ignorer l’en-tête entier par les navigateurs modernes.
Pour un site sans scripts tiers, un premier brouillon peut reprendre la politique recommandée par l’OWASP Secure Headers Project :
default-src 'self'; form-action 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'none'; upgrade-insecure-requestsElle bloque les scripts et styles inline (écrits directement dans le HTML) et tout ce qui vient d’autres hôtes : attendez-vous à de nombreux rapports au début, d’où le passage par le mode Report-Only (section 8). Ne reprenez que la ligne CSP : l’ensemble complet du projet contient aussi des valeurs comme Cache-Control: no-store et Clear-Site-Data, qui désactiveraient la mise en cache et effaceraient à chaque réponse les cookies et données stockées du visiteur. Sur les réponses d’API en JSON, que le navigateur n’affiche pas, la CSP apporte peu.
4. HSTS : monter max-age par paliers et réfléchir avant le préchargement
Strict-Transport-Security demande au navigateur de n’utiliser que HTTPS pour l’hôte et de convertir automatiquement les requêtes http:// suivantes. Le navigateur ignore l’en-tête reçu en HTTP simple : envoyez-le sur les réponses HTTPS, pas sur la redirection de HTTP vers HTTPS. À lui seul, il ne protège pas la toute première connexion d’un visiteur. Dans ses recommandations pour la mise en œuvre d’un site web, l’ANSSI juge nécessaire de mettre en œuvre HSTS contre les attaques de type « Man-in-the-Middle », en rappelant qu’un accès durable en HTTPS en est le prérequis.
Anticipez la contrepartie : sur un hôte HSTS, le visiteur ne peut pas passer outre une erreur de certificat, si bien qu’un certificat expiré bloque les visiteurs qui reviennent. Les certificats TLS publics émis depuis le 15 mars 2026 ne peuvent pas dépasser 200 jours de validité (CA/Browser Forum), et Let’s Encrypt n’envoie plus de rappels d’expiration par e-mail : mettez d’abord en place le renouvellement automatique et votre propre surveillance des échéances. Le guide TLS et en-têtes de sécurité traite du côté certificat.
Relevez max-age (en secondes) par paliers, comme le recommande hstspreload.org, en vérifiant à chaque étape que rien ne casse : 300 (5 minutes), 604800 (1 semaine), 2592000 (1 mois), puis 31536000 (1 an) ou 63072000 (2 ans, la valeur retenue par l’OWASP). max-age=0 supprime la politique, mais seulement s’il est reçu en HTTPS, et seulement pour les visiteurs qui reviennent et le reçoivent. Ajoutez includeSubDomains une fois que tous les sous-domaines fonctionnent en HTTPS, et faites aussi envoyer l’en-tête par chaque sous-domaine.
Le préchargement (preload) inscrit votre domaine dans les navigateurs eux-mêmes, si bien que même la première visite passe en HTTPS. Le site qui gère les inscriptions, hstspreload.org, recommande désormais HSTS mais pas le préchargement : Chrome et Safari convertissent déjà les navigations HTTP en HTTPS, le préchargement apporte donc peu, et un retrait de la liste met des mois à atteindre les utilisateurs. La fiche OWASP sur les en-têtes HTTP garde preload dans son exemple, alors que la valeur recommandée par l’OWASP Secure Headers Project ne le contient pas. Ne l’ajoutez pas par défaut et ne le recopiez pas depuis un modèle.
6. En-têtes à retirer : X-XSS-Protection et autres reliquats
- X-XSS-Protection activait dans les anciens navigateurs un filtre qui pouvait lui-même créer des failles XSS (MDN). L’OWASP conseille de ne pas l’envoyer, ou de le désactiver avec
0; la CSP le remplace. - Expect-CT : l’OWASP déconseille de l’utiliser et, en citant Mozilla, recommande de le retirer des configurations existantes.
- Public-Key-Pins (HPKP) a été retiré de Chromium en 2018 et n’est pris en charge par aucun navigateur moderne.
- Feature-Policy a été remplacé par Permissions-Policy.
Server et X-Powered-By révèlent le logiciel utilisé, parfois avec son numéro de version. L’OWASP suggère de les supprimer ou de les rendre peu informatifs, mais son propre guide de test parle de sécurité par l’obscurité, et MDN rappelle que tenir les logiciels à jour compte davantage. Retirez les numéros de version et consacrez l’effort aux mises à jour. Sous nginx, server_tokens off; retire la version, pas l’en-tête. Sous Apache, ServerTokens Prod réduit l’en-tête à « Apache », mais cette directive se règle dans la configuration du serveur, pas dans un .htaccess.
7. Une base à copier pour nginx, Apache et les hébergeurs statiques
Cette base nginx pose les en-têtes à faible risque, démarre HSTS et la CSP en phase de test et redirige HTTP vers HTTPS sur le même hôte. Le paramètre always ajoute aussi les en-têtes aux réponses d’erreur.
server {
listen 80;
server_name example.com;
return 301 https://example.com$request_uri;
}
server {
listen 443 ssl;
server_name example.com;
# ssl_certificate et ssl_certificate_key ici
server_tokens off;
add_header Strict-Transport-Security "max-age=300" 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;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Cross-Origin-Opener-Policy "same-origin" always;
add_header Content-Security-Policy-Report-Only "default-src 'self'; form-action 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'self'" always;
}Deux comportements documentés du module headers de nginx expliquent bien des en-têtes manquants. Sans always, add_header ne s’applique qu’aux codes 200, 201, 204, 206, 301, 302, 303, 304, 307 et 308 : les pages 404 et 500 partent sans les en-têtes. Et les directives add_header ne sont héritées du niveau supérieur que si le niveau courant n’en définit aucune : un seul add_header dans un bloc location y fait disparaître tous les en-têtes de sécurité définis au niveau server. Répétez les en-têtes, utilisez include avec un fichier commun ou, à partir de nginx 1.29.3, add_header_inherit merge;.
Sur un hébergement mutualisé sous Apache, on n’a souvent la main que sur le fichier .htaccess à la racine du site. La documentation de mod_headers y autorise la directive Header lorsque l’hébergeur permet les surcharges de type FileInfo, et le mot-clé always y joue le même rôle que sous nginx : les en-têtes sont ajoutés même aux réponses d’erreur.
<IfModule mod_headers.c>
Header always set X-Content-Type-Options "nosniff"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set Content-Security-Policy-Report-Only "default-src 'self'; form-action 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'self'"
</IfModule>Si mod_headers n’est pas chargé, le bloc IfModule est simplement ignoré : pas d’erreur 500, mais pas d’en-têtes non plus, d’où l’intérêt de vérifier avec curl. Apache tient deux tables distinctes pour Header set et Header always set, et la fiche OWASP prévient que l’usage des deux peut produire des doublons. Si l’hébergeur ou l’application risque de poser déjà un en-tête, la fiche conseille de le retirer d’abord avec Header unset, puis de le poser avec Header always set ; vérifiez ensuite avec curl qu’il n’apparaît qu’une fois.
Les hébergeurs statiques comme Cloudflare Pages et Netlify lisent un fichier _headers déployé avec le site. Cet exemple suit le format documenté par Cloudflare, que Netlify utilise aussi :
/*
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
X-Frame-Options: SAMEORIGIN
Content-Security-Policy-Report-Only: default-src 'self'; form-action 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'self'Ces fichiers ont leurs limites. Cloudflare Pages n’applique pas ce fichier aux réponses produites par les Pages Functions, accepte au plus 100 règles d’en-têtes de 2 000 caractères par ligne au maximum, et joint les valeurs par une virgule quand le même en-tête est appliqué deux fois. Netlify n’applique les en-têtes personnalisés qu’aux fichiers qu’il sert lui-même, pas aux contenus relayés par proxy, aux fonctions, aux edge functions ni aux pages rendues côté serveur ; ces réponses doivent poser leurs propres en-têtes. HSTS est absent des exemples .htaccess et _headers : vérifiez avec curl ce que l’hébergeur envoie déjà avant de l’ajouter.
8. Déployer par étapes et éviter les erreurs courantes
- Ajoutez nosniff, Referrer-Policy, Permissions-Policy et la protection contre l’intégration, puis testez la connexion, le paiement et les widgets intégrés.
- Envoyez la CSP provisoire en
Content-Security-Policy-Report-Only. Rien n’est bloqué ; les violations s’affichent dans la console du navigateur, et sur un point de collecte des rapports si la politique en désigne un. Testez les parcours importants, y compris les pages accessibles après connexion, et ajustez la politique. - Démarrez HSTS avec un
max-agecourt et relevez-le par paliers. - Appliquez la CSP. Une politique Report-Only plus stricte peut tourner à côté pour tester le resserrement suivant.
- Relancez les contrôles curl après chaque changement de serveur, de CDN ou de framework.
Erreurs courantes :
- Des en-têtes sur une partie des réponses seulement. La page d’accueil les envoie ; la page 404, l’API, les fichiers statiques ou une page de connexion servie à part, non.
- Changer d’hôte et de schéma dans la même redirection. Si
http://example.comredirige directement vershttps://www.example.com, le navigateur ne reçoit jamais HSTS pourexample.com. Redirigez d’abord vers HTTPS sur le même hôte, envoyez HSTS sur cette réponse HTTPS, puis seulement redirigez verswww. - Le CDN écrase les en-têtes de l’origine. Un CDN ou un proxy peut ajouter, remplacer, supprimer ou dupliquer des en-têtes. Décidez quelle couche porte chaque en-tête et confirmez le résultat avec curl.
- Une CSP qui autorise tout. Une politique remplie de
'unsafe-inline','unsafe-eval'ou*pour faire taire les erreurs passe un contrôle de présence mais ne bloque pas grand-chose. - includeSubDomains trop tôt. Un sous-domaine oublié qui ne fonctionne qu’en HTTP devient inaccessible pour les navigateurs qui ont mémorisé la politique.
Les en-têtes ne sont qu’une couche. La checklist de mise en ligne les replace à côté du DNS, de TLS et des redirections, et le guide pour tester la sécurité d’un site web couvre la connexion, les permissions et une routine de revue reproductible.
9. Comment le snapshot gratuit de Sitelemetry contrôle les en-têtes
Le snapshot gratuit exécute huit contrôles passifs sur une origine publique, sans inscription ; l’un d’eux lit les en-têtes de sécurité HTTP. Ce n’est pas un test d’intrusion, ni l’audit des six domaines.
- Il demande la page d’accueil de l’origine saisie (le chemin et les paramètres sont ignorés), suit jusqu’à cinq redirections et juge la réponse finale. Aucune autre page n’est demandée.
- Il vérifie surtout la présence des en-têtes. Une CSP absente, l’absence de HSTS sur une cible HTTPS, l’absence de protection contre l’intégration et
Access-Control-Allow-Origin: *sont classés de gravité moyenne. Un X-Content-Type-Options autre quenosniff, l’absence de Referrer-Policy et tout en-têteServerouX-Powered-Bysont classés faibles :Server: nginxsans numéro de version produit donc quand même un signal faible. Les cookies posés par cette réponse sans HttpOnly, ou sans Secure en HTTPS, sont classés moyens ; SameSite n’est pas vérifié. - Une note de durcissement distincte (de A à F) évalue l’ensemble des en-têtes présents avec le résultat TLS, et accorde moins de points à une CSP qui autorise
'unsafe-inline'(ou'unsafe-eval'pour les scripts). Permissions-Policy et COOP ne comptent que dans cette note. - Le contrôle distinct de la redirection HTTPS dépend de ce que vous saisissez. Pour un domaine saisi sans préfixe (
example.com) ou une adresse enhttps://, il signale comme faible unmax-ageHSTS inférieur à 180 jours, ce qui est normal pendant une montée par paliers, et cherche des références enhttp://dans le HTML de la page (contenu mixte) ; il ne teste pas la redirection de HTTP vers HTTPS. Celle-ci n’est testée que si vous saisissez l’adresse enhttp://, et dans ce cas, le contrôle TLS n’est pas effectué et l’absence de HSTS n’est pas signalée.
Le résultat affiche un score, la note de durcissement, le nombre de signaux de risque et de contrôles réussis, et jusqu’à trois signaux, les risques en premier. Il ne liste pas chaque en-tête avec sa valeur : utilisez les DevTools ou curl pour cela, ainsi que pour les réponses que le snapshot ne demande pas.
Questions fréquentes
Comment vérifier les en-têtes de sécurité de mon site ?
Dans les outils de développement du navigateur, ouvrez le panneau Réseau, rechargez la page, sélectionnez le document HTML et lisez les en-têtes de réponse. Dans un terminal, curl -sS -D - -o /dev/null https://example.com/ les affiche. Contrôlez aussi l’adresse en http://, une page 404, une réponse d’API et un fichier statique, car leurs en-têtes diffèrent souvent.
Quels en-têtes de sécurité HTTP mettre en place en premier ?
Commencez par X-Content-Type-Options: nosniff, Referrer-Policy, Permissions-Policy et la protection contre l’intégration, qui risquent le moins de casser quelque chose ; testez quand même les scripts, la connexion et les widgets intégrés ensuite. Testez ensuite une Content-Security-Policy en mode Report-Only et relevez le max-age de HSTS par paliers.
Faut-il encore envoyer X-XSS-Protection ?
Non. Supprimez-le ou envoyez X-XSS-Protection: 0, et appuyez-vous sur une Content-Security-Policy. L’ancien filtre qu’il pilotait dans les navigateurs pouvait lui-même créer des failles XSS.
X-Frame-Options sert-il encore si j’utilise frame-ancestors ?
La directive CSP frame-ancestors le remplace dans les navigateurs qui la prennent en charge, et l’ANSSI qualifie X-Frame-Options d’en-tête non standard rendu obsolète par CSP. X-Frame-Options: DENY ou SAMEORIGIN reste un repli raisonnable pour les anciens navigateurs, à condition que les deux en-têtes autorisent la même chose. N’utilisez pas ALLOW-FROM : les navigateurs modernes ignorent alors l’en-tête entier.
Faut-il inscrire mon domaine sur la liste de préchargement HSTS ?
En général, non. Le site d’inscription, hstspreload.org, recommande désormais HSTS mais pas le préchargement, car Chrome et Safari convertissent déjà les navigations HTTP en HTTPS. Un retrait de la liste met en outre des mois à atteindre les utilisateurs.
Les en-têtes de sécurité suffisent-ils à sécuriser mon site ?
Pas à eux seuls. Ils limitent les dégâts d’un script injecté, du détournement de clic, d’un retour forcé vers HTTP et du vol de cookies. Ils ne corrigent ni un code vulnérable, ni des logiciels obsolètes, ni un contrôle d’accès trop faible.
Sources et lectures
- MDN : guide Content Security Policy (CSP)developer.mozilla.org
- MDN (en français) : en-tête Content-Security-Policydeveloper.mozilla.org
- MDN : directive CSP frame-ancestorsdeveloper.mozilla.org
- MDN : en-tête Strict-Transport-Securitydeveloper.mozilla.org
- MDN : en-tête Set-Cookie et attributs des cookiesdeveloper.mozilla.org
- OWASP : HTTP Headers Cheat Sheetcheatsheetseries.owasp.org
- OWASP Secure Headers Project : valeurs d’en-têtes recommandéesraw.githubusercontent.com
- ANSSI : recommandations pour la mise en œuvre d’un site web (standards de sécurité côté navigateur)messervices.cyber.gouv.fr
- HSTS Preload List Submissionhstspreload.org
- nginx : module ngx_http_headers_module (add_header)nginx.org
- Apache HTTP Server : module mod_headershttpd.apache.org
- Cloudflare Pages : Headersdevelopers.cloudflare.com
- Netlify : Custom headersdocs.netlify.com
Préparé par la rédaction de Sitelemetry. Les sources citées permettent d’approfondir chaque sujet.



