Vérifier la sécurité de son site en une minute : les en-têtes HTTP qui comptent
Les en-têtes HTTP de votre site disent en quelques secondes si les protections de base sont en place. Explication de chaque en-tête, outil de vérification en ligne, et configurations prêtes à copier pour Nginx, Apache et Node.js.
À chaque page chargée, votre serveur envoie au navigateur une dizaine de lignes invisibles : les en-têtes HTTP. Certaines indiquent au navigateur ce qu’il a le droit de faire avec la page, d’autres révèlent par inadvertance quelle technologie tourne derrière, et dans quelle version. Lire ces lignes prend quelques secondes et donne une première image du soin apporté à la configuration.
Cet article explique ce que chaque en-tête protège, puis vous propose un outil qui interroge votre site et vous dit ce qui manque. Il est en bas de cette page, et sur sa page dédiée.
Ce qu’un en-tête peut empêcher, et ce qu’il ne peut pas
Prenons un cas courant : un champ de commentaire mal filtré laisse passer un bout de JavaScript, ou une bibliothèque chargée depuis un CDN est remplacée par une version piégée. Sans protection, le navigateur exécute ce code comme s’il venait de vous. Avec une politique de sécurité du contenu correctement écrite, il refuse tout script qui ne provient pas d’une source que vous avez listée. L’attaquant doit alors compromettre un domaine précis, et non glisser du code n’importe où.
C’est le principe de tous les en-têtes de sécurité. Ils ne corrigent pas une faille dans votre code. Ils limitent ce qu’un attaquant peut en faire.
Ils ont aussi une limite, et les boutiques Shopify détournées en octobre 2026 l’illustrent bien. Le code malveillant y était servi par l’éditeur d’une application légitime, donc depuis un domaine que le marchand aurait de toute façon autorisé. Une politique de sécurité n’aurait rien bloqué. Quand le danger vient d’une extension de confiance, la seule défense est de limiter le nombre d’extensions et de les surveiller.
Les en-têtes passés en revue
HTTPS et Strict-Transport-Security
Le HTTPS chiffre les échanges. Mais un visiteur qui tape votre adresse sans le préfixe arrive d’abord en HTTP, et c’est à ce moment qu’une attaque sur un réseau public peut l’intercepter. L’en-tête HSTS demande au navigateur de ne plus tenter le HTTP pour votre domaine, pendant la durée indiquée. Il ne protège qu’à partir de la deuxième visite : le navigateur doit avoir vu l’en-tête une première fois pour s’en souvenir. Pour couvrir aussi la toute première visite, il faut inscrire le domaine sur la liste de préchargement des navigateurs, avec la directive preload. Six mois est le minimum utile, un an est la valeur courante.
Content-Security-Policy
C’est l’en-tête le plus puissant, et le plus délicat à écrire. Il liste les sources autorisées pour les scripts, les styles, les images, les polices et les connexions. Tout ce qui n’y figure pas est bloqué. Une politique qui autorise * pour les scripts n’apporte rien. Une politique trop stricte casse le site. La bonne méthode : démarrer en mode rapport seul, lire les violations remontées par les navigateurs, puis basculer en mode bloquant.
X-Frame-Options et frame-ancestors
L’en-tête X-Frame-Options et la directive frame-ancestors de la CSP empêchent qu’une page de votre site soit affichée dans un cadre invisible sur un site tiers. Le piège classique : un bouton attrayant superposé à votre bouton « Valider », pour faire cliquer le visiteur à son insu. La directive remplace progressivement l’en-tête, mais les deux coexistent sans conflit.
Referrer-Policy
Quand un visiteur clique sur un lien externe depuis votre site, le navigateur transmet l’adresse de la page d’origine. Avec une politique permissive comme unsafe-url, un site tiers voit l’adresse complète, paramètres inclus. La valeur strict-origin-when-cross-origin ne transmet que l’origine, c’est-à-dire le protocole, le domaine et le port. C’est aussi la valeur par défaut des navigateurs récents : l’absence de l’en-tête n’expose donc pas vos visiteurs. L’ajouter rend ce choix explicite et couvre les anciens navigateurs.
Permissions-Policy
Cet en-tête désactive les accès que votre site n’utilise pas : caméra, micro, géolocalisation. Il est facultatif, mais il ferme une porte qu’un script injecté pourrait ouvrir.
Les attributs des cookies
Un cookie marqué Secure ne circule qu’en HTTPS. Un cookie marqué HttpOnly est invisible pour le JavaScript de la page, donc pour un script injecté. L’attribut SameSite, avec la valeur Lax ou Strict, empêche qu’il soit envoyé depuis un site tiers, ce qui coupe les requêtes forgées. Un cookie de session sans ces trois attributs est le premier objectif d’une attaque par injection.
Les versions exposées
Les en-têtes Server et X-Powered-By annoncent parfois la version exacte du serveur ou du langage : nginx/1.24.0, PHP/8.3.20. Cette information ne sert à rien pour vos visiteurs. Pour un attaquant, elle indique directement quelles failles tester. Depuis les correctifs du 21 octobre 2026, un site qui annonce une version de PHP inférieure à 8.2.35, 8.3.36, 8.4.27 ou 8.5.12 signale publiquement qu’il est vulnérable à php2shell, une faille exploitée en conditions réelles. Même logique pour Node.js avec Node2Shell : les versions corrigées sont 22.23.4, 24.22.1 et 26.12.1. L’outil ci-dessous compare la version annoncée à ces seuils.
Comment corriger
Les en-têtes se configurent en un seul endroit, selon votre serveur. Chaque bloc ci-dessous est directement utilisable, à adapter pour la CSP selon les ressources externes que votre site charge réellement.
Nginx, dans le bloc server. Attention au piège le plus courant : dès qu’un bloc location contient sa propre directive add_header, il n’hérite plus de celles du bloc server. Dans ce cas, répétez les en-têtes de sécurité dans ce bloc, ou regroupez-les dans un fichier inclus aux deux niveaux.
# Force le HTTPS pendant un an, sous-domaines compris
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# Scripts et styles limités au domaine lui-même ; adapter selon vos services externes
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; frame-ancestors 'self'" 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;
# Ne pas annoncer la version de Nginx
server_tokens off;
Apache, dans le fichier .htaccess ou la configuration du site, avec le module headers activé :
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; frame-ancestors 'self'"
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=()"
# Supprime l'en-tête X-Powered-By ajouté par PHP
Header unset X-Powered-By
Pour masquer la version d’Apache, la directive ServerTokens Prod se place dans la configuration principale du serveur (httpd.conf ou apache2.conf), jamais dans un .htaccess : elle y provoque une erreur 500.
PHP, pour masquer la version quel que soit le serveur, dans php.ini :
; Supprime l'en-tête X-Powered-By: PHP/x.y.z
expose_php = Off
Node.js avec Express, la bibliothèque helmet pose l’ensemble en un seul appel. Elle ne gère pas Permissions-Policy, qu’on ajoute à la main pour obtenir la même couverture que les configurations Nginx et Apache ci-dessus :
import helmet from 'helmet';
// Pose HSTS, CSP, nosniff, frame-ancestors, Referrer-Policy et retire X-Powered-By
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", 'data:', 'https:'],
},
},
}));
// Permissions-Policy n'est pas couvert par helmet
app.use((request, response, next) => {
response.setHeader('Permissions-Policy', 'camera=(), microphone=(), geolocation=()');
next();
});
Shopify : vous ne contrôlez pas les en-têtes, Shopify les gère pour vous. Votre levier est ailleurs : le nombre d’applications installées et le test régulier de votre tunnel de commande en navigation privée.
Ce que l’outil ne voit pas
La vérification ci-dessous lit uniquement les en-têtes publics de votre page d’accueil, une seule fois. Elle ne teste pas votre code, vos formulaires, vos extensions ni votre base de données. Un site peut obtenir tous les points verts et rester vulnérable par une extension WordPress obsolète. À l’inverse, un site avec plusieurs points orange n’est pas forcément piraté : il manque simplement de garde-fous.
Prenez le résultat pour ce qu’il est : un premier diagnostic. Il reste à vérifier les versions que votre serveur n’annonce pas, donc que l’outil ne peut pas lire, et, pour un site qui encaisse des paiements ou stocke des données clients, à faire réaliser un audit complet. Si le résultat vous inquiète, ou si vous ne savez pas qui s’occupe de ces réglages sur votre site, écrivez-moi.
Outil
Votre site est-il correctement configuré ?
Entrez l’adresse de votre site. Le serveur l’interroge une fois, lit ses en-têtes HTTP et vous dit ce qui manque. Rien n’est stocké.
Résultat pour
Technologies détectées
Site Shopify : le serveur est géré par Shopify, les en-têtes sont les siens. Le vrai risque vient des applications installées. Testez votre tunnel de commande en navigation privée et vérifiez que vous restez sur votre domaine ou sur shopify.com.
À corriger en premier
Rien d’urgent. Les points ci-dessous sont tous corrects ou informatifs.
Le détail par thème
Cette vérification lit uniquement les en-têtes publics de la page d’accueil. Elle ne remplace pas un audit : un site peut passer tous ces points et rester vulnérable dans son code ou ses extensions.
Un point rouge ou plusieurs oranges ? Parlons-en