En bref : les en-têtes de sécurité sont des instructions du serveur web au navigateur qui protègent les visiteurs contre des attaques comme le cross-site scripting, le clickjacking et les connexions non chiffrées. Les principaux sont HSTS, Content-Security-Policy, X-Content-Type-Options, la protection contre les cadres étrangers, Referrer-Policy et Permissions-Policy. Ils constituent un renforcement judicieux, mais ne remplacent pas les mises à jour sur le serveur.
Ce qu'apportent les en-têtes de sécurité et ce qu'ils n'apportent pas
À chaque consultation de page, le serveur web envoie, en plus du contenu, des en-têtes. Certains d'entre eux pilotent des fonctions de sécurité du navigateur. On peut ainsi par exemple prévoir qu'une page ne soit chargée que via HTTPS ou que le navigateur n'exécute aucun script provenant de domaines étrangers.
Pour les exploitants, la mise en perspective est importante : les en-têtes protègent en premier lieu les visiteurs, par exemple contre l'interception de sessions ou contre des formulaires manipulés. Ils ne comblent aucune faille sur le serveur. Une vulnérabilité dans PHP, dans le CMS ou dans une extension subsiste, quelle que soit la qualité des en-têtes. Associés à un code propre, ils limitent toutefois nettement les conséquences de nombreuses erreurs.
Les principaux en-têtes de sécurité en un coup d'œil
| En-tête | Objectif | Recommandation comme point de départ |
|---|---|---|
| Strict-Transport-Security (HSTS) | impose HTTPS pour les consultations futures | max-age=31536000; includeSubDomains |
| Content-Security-Policy (CSP) | définit les sources autorisées pour scripts, images, cadres | à adapter, d'abord en Report-Only |
| X-Content-Type-Options | empêche le navigateur de deviner les types de fichiers | nosniff |
| X-Frame-Options ou CSP frame-ancestors | empêche l'intégration dans des sites étrangers (clickjacking) | SAMEORIGIN ou frame-ancestors 'self' |
| Referrer-Policy | limite quelle adresse est transmise à d'autres sites | strict-origin-when-cross-origin |
| Permissions-Policy | désactive des fonctions du navigateur comme la caméra ou la localisation | n'autoriser que les fonctions nécessaires |
Ne définissez HSTS que lorsque tous les sous-domaines sont accessibles de façon fiable via HTTPS. Le navigateur mémorise l'instruction pendant la durée indiquée ; une erreur ne peut alors pas être annulée immédiatement. Commencez le cas échéant par une courte durée et augmentez-la après des tests réussis. L'option supplémentaire preload inscrit durablement le domaine dans des listes des éditeurs de navigateurs et ne devrait être définie qu'après un examen minutieux.
Les en-têtes ne sont en outre pas le seul endroit où le navigateur offre une protection. Les cookies devraient porter les attributs Secure, HttpOnly et SameSite afin que les sessions ne soient pas interceptées via des connexions non chiffrées ou des scripts. La façon de le configurer en PHP est décrite dans le guide sur les sessions.
Définir les en-têtes de sécurité dans Nginx
Dans Nginx, les en-têtes se placent dans le bloc server du site concerné. L'ajout de always fait en sorte qu'ils soient aussi envoyés pour les pages d'erreur.
server {
# ...
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header Content-Security-Policy-Report-Only "default-src 'self'; img-src 'self' data:; object-src 'none'; base-uri 'self'; frame-ancestors 'self'; form-action 'self'" always;
server_tokens off;
}
Une particularité de Nginx : si un bloc location définit ses propres instructions add_header, les en-têtes du bloc server n'y sont pas repris. Contrôlez donc aussi les sous-pages et les fichiers statiques. Un renforcement supplémentaire pour cette combinaison est décrit dans Sécuriser Nginx avec PHP-FPM.
Définir les en-têtes de sécurité dans Apache
Sous Apache, vous avez besoin du module mod_headers. Les instructions se placent dans le VirtualHost ou, si vous n'y avez pas accès, dans le .htaccess.
<IfModule mod_headers.c>
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
Header always set Content-Security-Policy-Report-Only "default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'"
</IfModule>
ServerTokens Prod
ServerSignature Off
ServerTokens et ServerSignature relèvent de la configuration principale. Ils empêchent le serveur d'indiquer sa version exacte dans les réponses et les pages d'erreur. Dans php.ini, vous obtenez la même chose pour PHP avec expose_php = Off.
Introduire progressivement la Content Security Policy
La Content Security Policy est l'en-tête le plus efficace, mais aussi le plus exigeant. Elle définit de quelles sources scripts, feuilles de style, images, polices et cadres peuvent être chargés. Si un script introduit est rechargé depuis un domaine étranger, le navigateur le bloque.
Les sites modernes intègrent souvent des outils d'analyse, des prestataires de paiement, des services de cartes ou des vidéos. Une politique trop stricte paralyse alors des fonctions. Procédez donc par étapes :
- Commencer d'abord avec
Content-Security-Policy-Report-Only. Le navigateur signale les violations dans la console de développement ou à une adresse collectrice, mais ne bloque rien. - Recenser toutes les sources nécessaires et les autoriser de façon ciblée, au lieu d'utiliser des jokers généraux.
- Externaliser progressivement les scripts en ligne dans des fichiers ou les munir de nonces afin de pouvoir renoncer à
'unsafe-inline'. - Ne passer à
Content-Security-Policyqu'après une phase de test sans rapport inattendu.
La CSP complète un échappement propre dans le code, mais ne le remplace pas. Le guide Prévenir le cross-site scripting en PHP explique comment sécuriser correctement les sorties en PHP.
Contrôler les en-têtes et éviter les erreurs typiques
Après chaque modification, vous devriez vérifier que les en-têtes arrivent réellement. Cela se fait sans outil supplémentaire avec curl :
# Tester la configuration et la recharger
nginx -t && systemctl reload nginx
# Afficher les en-têtes de la page d'accueil et d'un fichier statique
curl -sI https://www.example.de/ | grep -iE 'strict|content-security|x-content|x-frame|referrer|permissions|server'
curl -sI https://www.example.de/favicon.ico | grep -iE 'strict|x-content'
Les erreurs typiques sont des en-têtes définis en double lorsque le serveur web et l'application envoient les mêmes en-têtes, un CDN placé en amont qui supprime ou écrase des en-têtes, et des en-têtes qui n'apparaissent que sur la page d'accueil mais pas lors des redirections ou sur les pages d'erreur. Vérifiez en outre après les mises à jour du CMS ou des extensions de sécurité si les en-têtes ont changé.
Définissez donc un endroit où les en-têtes sont maintenus, de préférence le serveur web ou le service placé en amont. De nombreuses extensions de CMS proposent aussi des réglages pour les en-têtes de sécurité. C'est pratique, mais conduit facilement à des indications en double ou contradictoires si le serveur définit en plus des en-têtes. Pour des tests ponctuels, les outils de développement du navigateur conviennent aussi : dans l'onglet Réseau, vous voyez pour chaque requête les en-têtes de réponse, et la console affiche les violations de la Content Security Policy.
Comment PHP SOS aide-t-il concrètement ?
- Nous examinons les en-têtes actuels de tous vos sites, y compris derrière un CDN et un proxy, et faisons apparaître les lacunes et les contradictions.
- Nous définissons les en-têtes de façon centralisée dans le serveur web dans le cadre du renforcement de serveur et testons la page d'accueil, les sous-pages et les pages d'erreur.
- Nous introduisons la Content Security Policy en mode Report-Only, analysons les rapports et l'activons après concertation.
- Là où des modifications du code ne sont pas possibles immédiatement, nous complétons la protection par des règles WAF et un correctif virtuel.
Questions fréquentes
Que sont les en-têtes de sécurité ?
Les en-têtes de sécurité sont des indications supplémentaires dans la réponse du serveur web. Ils indiquent par exemple au navigateur qu'il ne doit charger la page que via HTTPS, n'exécuter aucun script étranger ou ne pas afficher la page dans un cadre étranger. Ils protègent surtout les visiteurs.
Les en-têtes de sécurité protègent-ils contre PHP2Shell ?
Non. PHP2Shell est une faille de PHP sur le serveur, alors que les en-têtes agissent dans le navigateur du visiteur. Contre PHP2Shell, aident la mise à jour vers une version de PHP corrigée et le redémarrage de tous les workers. Les en-têtes sont un renforcement complémentaire contre d'autres types d'attaque.
Une Content Security Policy peut-elle casser mon site ?
Oui, une politique trop stricte bloque des scripts, des polices ou des contenus intégrés nécessaires. C'est pourquoi on l'introduit d'abord en mode rapport seul, on analyse les rapports et on ne passe qu'ensuite à l'application effective.
X-XSS-Protection a-t-il encore un intérêt ?
Non. Les navigateurs actuels n'évaluent plus cet en-tête, et la recommandation est de l'omettre ou de le mettre à 0. Une protection contre le cross-site scripting est assurée par un échappement propre dans le code et une Content Security Policy.