Guides · 16 minutes de lecture
Les en-têtes de sécurité HTTP, expliqués un par un
On les recopie souvent sans savoir ce qu’ils font. Voici ce que chacun protège, ce qu’il ne protège pas, et lesquels valent vraiment le détour sur un site ordinaire.
Un en-tête de sécurité est une instruction que votre serveur envoie au navigateur avec chaque page. Le navigateur, lui, obéit. C’est ce qui rend ces en-têtes intéressants : ils déplacent une partie de la défense côté client, là où l’attaque se produit.
Ils ne remplacent rien. Un site mal codé reste vulnérable. Mais plusieurs d’entre eux coûtent une ligne de configuration et ferment des portes que rien d’autre ne ferme.
Strict-Transport-Security (HSTS)
Ce qu’il fait — il ordonne au navigateur de n’utiliser que HTTPS sur votre domaine, pendant une durée donnée, quoi qu’il arrive.
Le problème qu’il résout — vous redirigez déjà HTTP vers HTTPS, donc
tout va bien ? Pas tout à fait. Quelqu’un qui tape monsite.fr dans sa barre
d’adresse émet d’abord une requête en clair. Sur un réseau hostile — un wifi public —
cette première requête peut être interceptée et détournée avant même que votre
redirection s’applique. HSTS supprime cette fenêtre : après une première visite réussie,
le navigateur refuse de repasser en clair.
La prudence à avoir — c’est le seul en-tête de cette liste qui peut vous mettre en difficulté. Une fois envoyé avec une durée d’un an, les navigateurs de vos visiteurs refuseront le HTTP pendant un an. Si votre certificat expire et n’est pas renouvelé, le site devient inaccessible, sans possibilité de contournement. Ne l’activez qu’avec un renouvellement automatique en place et vérifié.
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
La faille que HSTS ne ferme pas : la toute première visite
HSTS fonctionne par mémorisation : le navigateur n’applique la règle qu’après avoir reçu l’en-tête au moins une fois. Un visiteur qui arrive sur votre site pour la première fois émet donc toujours sa requête initiale en clair — c’est exactement la requête que HSTS est censé protéger. On appelle ça la confiance à la première utilisation, et c’est une limite structurelle, pas un défaut de configuration.
C’est la seule raison d’être de la liste de préchargement : une liste de domaines intégrée directement au code des navigateurs, qui les fait passer en HTTPS avant la première requête.
Le préchargement est une porte à sens unique
Y entrer est facile. En sortir ne l’est pas — et c’est le point que les tutoriels omettent presque toujours. La documentation officielle de la liste est explicite : l’inscription « ne peut pas être facilement défaite », et une radiation met des mois à atteindre les utilisateurs, le temps qu’une version de Chrome se diffuse. Les autres navigateurs n’offrent aucune garantie de délai.
Entre-temps, tout visiteur dont le navigateur porte encore votre domaine dans sa liste refusera le HTTP. Si vous ne pouvez plus servir le HTTPS — certificat non renouvelé, changement d’hébergeur mal préparé, sous-domaine oublié — votre site est simplement inaccessible pour ces personnes, et vous ne pouvez rien y faire.
Les conditions d’inscription sont au nombre de quatre : un certificat valide, une
redirection de HTTP vers HTTPS sur le même hôte si le port 80 écoute, tous
les sous-domaines servis en HTTPS (y compris www s’il existe un
enregistrement DNS), et un en-tête portant max-age d’au moins
31536000, includeSubDomains et preload.
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
La règle à retenir : n’ajoutez le mot preload que si vous
vous engagez à servir ce domaine et tous ses sous-domaines en HTTPS pour des années.
Tant que ce n’est pas le cas, HSTS sans preload vous apporte déjà
l’essentiel du bénéfice, et reste réversible.
Le piège d’includeSubDomains
includeSubDomains étend la règle à tout ce qui se trouve sous
votre domaine. C’est ce qu’on veut en général, mais c’est aussi ce qui casse des choses
auxquelles on ne pense pas : un intranet en clair sur interne.monsite.fr,
un vieil outil sur legacy.monsite.fr, une machine de test, un sous-domaine
géré par un prestataire. Tous deviennent inaccessibles depuis les navigateurs ayant vu
l’en-tête, sans message d’erreur exploitable pour l’utilisateur.
Faites l’inventaire de vos sous-domaines avant, pas après.
La montée en puissance, concrètement
Ne passez pas directement à un an. La bonne séquence tient en trois paliers, en vérifiant à chaque fois que rien ne casse :
max-age=300 # cinq minutes, le temps de vérifier
max-age=86400 # un jour, pendant une semaine
max-age=31536000 # un an, une fois serein
Le raisonnement est simple : tant que max-age est court, une erreur se
corrige en attendant que la valeur expire. À un an, elle ne se corrige plus.
Content-Security-Policy (CSP)
Ce qu’il fait — il énumère les sources depuis lesquelles le navigateur a le droit de charger scripts, styles, images et polices. Tout le reste est refusé.
Le problème qu’il résout — l’injection de script. Si une faille permet à un attaquant d’insérer du code dans une de vos pages, une CSP correctement rédigée empêche ce code de s’exécuter ou de communiquer avec l’extérieur. C’est le plus puissant des en-têtes de cette liste, et de loin le plus délicat à écrire.
La difficulté — une CSP stricte casse tout ce qui n’a pas été prévu. Sur un site utilisant plusieurs services tiers, la rédiger correctement demande du travail, et la maintenir en demande encore. C’est pour cette raison qu’elle est largement absente en pratique.
La bonne méthode — commencez en mode observation. L’en-tête
Content-Security-Policy-Report-Only ne bloque rien mais signale ce qui
aurait été bloqué, dans la console du navigateur. Vous ajustez, puis vous basculez.
Pour un site statique sans script tiers, la politique tient en une ligne :
Header always set Content-Security-Policy "default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'"
Si vous utilisez des scripts tiers, il faudra les autoriser explicitement. Évitez
'unsafe-inline' sur script-src : c’est précisément ce que la
CSP est censée empêcher, et l’autoriser vide la politique de sa substance.
X-Content-Type-Options
Ce qu’il fait — il interdit au navigateur de deviner le type d’un fichier à partir de son contenu plutôt que de s’en tenir au type déclaré.
Le problème qu’il résout — un fichier téléversé par un utilisateur, servi comme une image, mais dont le contenu ressemble à du JavaScript, peut être exécuté par un navigateur trop serviable. Une seule valeur possible, aucun effet de bord, aucune raison de s’en passer.
Header always set X-Content-Type-Options "nosniff"
Referrer-Policy
Ce qu’il fait — il contrôle quelle information sur la page d’origine est transmise quand un visiteur suit un lien vers un autre site.
Le problème qu’il résout — par défaut, l’URL complète de la page courante part chez le site de destination. Si cette URL contient un identifiant, un jeton de réinitialisation ou simplement une page privée, vous venez de la divulguer. C’est autant un enjeu de confidentialité pour vos visiteurs qu’un enjeu de sécurité.
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Cette valeur transmet l’URL complète en interne, seulement le nom de domaine vers l’extérieur, et rien du tout si la destination est en HTTP. C’est le bon compromis : vos partenaires savent que le trafic vient de chez vous, sans en savoir plus.
Permissions-Policy
Ce qu’il fait — il désactive des fonctionnalités du navigateur pour votre site : caméra, micro, géolocalisation, capteurs.
Le problème qu’il résout — il réduit la surface d’attaque. Si votre site n’a aucune raison de demander l’accès à la caméra, l’interdire explicitement signifie qu’un script injecté ne pourra pas le faire non plus. Il vaut aussi pour les cadres : une régie publicitaire ou un lecteur vidéo intégré hérite de vos règles.
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
La syntaxe, et les deux erreurs que tout le monde fait
Chaque directive s’écrit fonctionnalité=(liste), les directives séparées
par des virgules. La liste peut prendre quatre formes :
() # personne, pas même vous
self # votre site et vos cadres de même origine
* # tout le monde, y compris les cadres tiers
"https://exemple.fr" # une origine précise, entre guillemets
Première erreur — écrire 'self' avec des apostrophes,
par habitude de la CSP. Dans une CSP, 'self' se met entre apostrophes ;
dans Permissions-Policy, self s’écrit nu. Les guillemets ne
servent qu’aux origines explicites.
Seconde erreur — écrire 'none' pour tout interdire. Ici,
l’interdiction totale s’écrit avec une liste vide, (). 'none'
n’existe pas dans cet en-tête.
Ces deux erreurs sont d’autant plus faciles à commettre que rien ne vous prévient : la spécification demande au navigateur d’ignorer purement et simplement une directive dont il ne reconnaît pas la fonctionnalité, et de passer à la suivante. C’est voulu — cela permet d’ajouter de nouvelles fonctionnalités sans casser les configurations existantes — mais l’effet de bord est qu’une faute de frappe n’émet aucune alerte. La directive est silencieusement sans effet.
À ne pas confondre avec Feature-Policy — c’est
l’ancien nom du même mécanisme, avec une syntaxe différente (espaces au lieu de
parenthèses). Il est obsolète. Si vous le trouvez dans une configuration héritée,
remplacez-le, ne l’empilez pas.
Pour mettre au point sans rien casser, il existe un mode observation,
Permissions-Policy-Report-Only, sur le même principe que celui de la CSP.
Une valeur de départ raisonnable pour un site ordinaire, qui n’a besoin d’aucune de ces fonctionnalités :
Header always set Permissions-Policy "accelerometer=(), autoplay=(), camera=(), display-capture=(), encrypted-media=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), midi=(), payment=(), usb=()"
X-Frame-Options et frame-ancestors
Ce qu’ils font — ils empêchent votre site d’être affiché dans un cadre sur un site tiers.
Le problème qu’ils résolvent — le détournement de clic. Un attaquant affiche votre site dans un cadre invisible, superpose ses propres éléments, et récupère les clics de l’utilisateur qui croit interagir avec autre chose. Sur un site avec des actions authentifiées, c’est une vraie attaque.
X-Frame-Options est l’ancien mécanisme, frame-ancestors dans
la CSP est le moderne. Les navigateurs récents privilégient le second quand les deux
sont présents. Mettre les deux ne coûte rien.
Header always set X-Frame-Options "SAMEORIGIN"
Ce qui ne sert à rien
Vous verrez encore X-XSS-Protection recommandé un peu partout. Il pilotait
un filtre que les navigateurs modernes ont retiré — Chrome l’a supprimé, Firefox ne
l’a jamais implémenté. Dans certaines configurations, ce filtre introduisait lui-même
des vulnérabilités. L’en-tête est aujourd’hui inutile au mieux. Ne le mettez pas ;
s’il est présent, retirez-le.
Vous verrez aussi Server et X-Powered-By présentés comme des
failles. Ils divulguent la version de votre serveur et de votre langage, ce qui aide un
attaquant à cibler ses tentatives. Les masquer est une bonne hygiène, mais c’est de
l’obscurité, pas de la sécurité : ça ne corrige aucune vulnérabilité réelle. À faire
après le reste, pas avant.
Où poser ces en-têtes — Apache, nginx, WordPress
Les exemples ci-dessus sont en syntaxe Apache, celle qu’on rencontre sur la plupart des
hébergements mutualisés. Ils vont dans le .htaccess à la racine du site, ou
mieux, dans la configuration du serveur quand vous y avez accès. Sur LiteSpeed, la même
syntaxe s’applique.
Sur nginx, la directive change de nom :
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
Le mot-clé always a son importance dans les deux cas : sans lui, l’en-tête
est omis sur les réponses d’erreur. Or une page 404 ou 500 mérite les mêmes protections
que les autres — c’est souvent là qu’un contenu inattendu s’affiche.
Autre détail qui coûte cher : sur nginx, un bloc location qui contient
add_header annule tous les add_header hérités du
niveau supérieur. Si vous ajoutez un en-tête dans un location,
vous devez y répéter tous les autres.
Le cas WordPress
Sur WordPress, trois voies s’offrent à vous, et elles ne se valent pas.
1. Le .htaccess. C’est la bonne réponse sur un hébergement
Apache ou LiteSpeed. Placez vos directives Header always set
en dehors du bloc # BEGIN WordPress / # END WordPress,
que WordPress réécrit sans prévenir lors d’une mise à jour des permaliens.
2. Un greffon de sécurité. Pratique, et acceptable — à condition de vérifier le résultat plutôt que de croire le tableau de bord. Beaucoup de greffons annoncent des en-têtes qu’ils ne posent pas dans toutes les configurations.
3. Le code, via le crochet send_headers, dans un greffon
maison ou le fichier functions.php de votre thème enfant :
add_action('send_headers', function () {
header('X-Content-Type-Options: nosniff');
header('Referrer-Policy: strict-origin-when-cross-origin');
});
Le piège des deux dernières méthodes — et il est réel. PHP ne s’exécute
que sur les requêtes traitées par WordPress. Vos feuilles de style, vos scripts, vos
images et vos polices sont servis directement par le serveur web, sans passer par PHP :
ils ne reçoivent aucun de ces en-têtes. Un
X-Content-Type-Options: nosniff posé en PHP protège vos pages et laisse
justement de côté les fichiers dont le type pourrait être mal deviné.
C’est la raison pour laquelle la configuration serveur reste supérieure au code : elle
s’applique à tout ce qui sort du site. Si vous ne devez retenir qu’une chose de cette
section : posez vos en-têtes dans le .htaccess ou la configuration nginx,
et servez-vous de PHP uniquement pour ce qui doit varier d’une page à l’autre.
Par où commencer
Si vous n’en mettez que trois, prenez X-Content-Type-Options,
Referrer-Policy et la protection anti-cadre : aucun effet de bord, une
ligne chacun, un bénéfice immédiat. HSTS ensuite, une fois le renouvellement de
certificat vérifié. La CSP en dernier, en mode observation d’abord.
Notre outil d’analyse vous dit lesquels sont déjà en place sur votre site et lesquels manquent.
Passer à l’action
À lire ensuite
Attaques par en-tête Host : comprendre le risque et corriger →
Le nom de domaine que reçoit votre serveur vient du client, pas de vous. Ce qu’un serveur ordinaire en fait par défaut, les trois exploitations réelles, et la configuration qui ferme la porte.
Choisir son hébergement web : les critères qui se vérifient →
Quatre critères d’hébergement se mesurent de l’extérieur en une minute, cinq autres se demandent avant de signer. Le prix n’en fait pas partie.
Ce guide est informatif et ne constitue pas un conseil juridique. La réglementation
évolue et son application dépend de votre situation.
Publié le 25/08/2026, mis à jour le
07/09/2026.
Sources : RFC 6797 (définition de HSTS et de la confiance à la première utilisation) ; hstspreload.org (conditions d’inscription et délai de radiation, cités depuis la page officielle de la liste) ; W3C, Permissions Policy (traitement des fonctionnalités non reconnues, § 9.2) ; MDN, Permissions-Policy (formes de liste d’autorisation) ; MDN, Content Security Policy ; WordPress, crochet send_headers ; nginx, add_header (règle d’héritage entre blocs) ; OWASP Secure Headers Project. Liens relevés le 07/09/2026.