Guide de correction

Comment configurer les en-têtes HTTP de sécurité via .htaccess vs Nginx

20 mai 2026

Les en-têtes HTTP de sécurité sont des en-têtes de réponse qui indiquent aux navigateurs d'appliquer des comportements de sécurité spécifiques lors du rendu d'une page. Ils se configurent au niveau du serveur web, pas dans WordPress, et n'ont aucun coût de performance à activer. Un site WordPress avec les bons en-têtes bloque le clickjacking, les rétrogradations vers du contenu mixte, les exploits de MIME-sniffing, et une grande partie des payloads de cross-site scripting. La configuration est un changement unique soit dans le .htaccess d'Apache, soit dans la config serveur de Nginx. Voici les sept en-têtes qui comptent en 2026, avec des snippets prêts à copier-coller pour les deux serveurs web.

Quels en-têtes HTTP de sécurité un site WordPress doit-il définir ?

Sept en-têtes couvrent le modèle de menace réaliste d'un site axé contenu. Par ordre de priorité :

  • Strict-Transport-Security (HSTS). Force les navigateurs à utiliser HTTPS pendant un an (ou plus) après la première visite, empêchant les attaques de HTTPS-stripping sur du WiFi public. Obligatoire si votre site a des utilisateurs connectés.
  • Content-Security-Policy (CSP). Indique au navigateur exactement quelles sources de JavaScript, CSS, images et polices sont autorisées. L'en-tête le plus impactant contre XSS, mais aussi le plus délicat à configurer sans casser votre site.
  • X-Frame-Options ou la directive CSP frame-ancestors. Empêche votre site d'être intégré dans un iframe sur un autre domaine, bloquant les attaques de clickjacking contre le formulaire de connexion.
  • X-Content-Type-Options: nosniff. Empêche les navigateurs de deviner le type de contenu d'une réponse, ce qui ferme une classe d'attaques "uploader une fausse image qui est en fait du JavaScript".
  • Referrer-Policy. Contrôle quelle quantité de l'URL actuelle est envoyée dans l'en-tête Referer lors des clics sortants. Les défauts fuient les query strings aux tiers ; strict-origin-when-cross-origin est la recommandation moderne.
  • Permissions-Policy (anciennement Feature-Policy). Désactive les fonctionnalités du navigateur que votre site n'utilise pas (caméra, micro, géolocalisation), réduisant l'exposition si jamais un script tiers tente d'y accéder.
  • Cross-Origin-Opener-Policy. Isole votre site des fenêtres popup qu'il ouvre, atténuant les attaques par canal auxiliaire de la classe Spectre. Requis pour que SharedArrayBuffer fonctionne.

Ce qui n'est plus recommandé : X-XSS-Protection (déprécié, les navigateurs l'ignorent), Public-Key-Pins (déprécié, causait trop de verrouillages) et Expect-CT (déprécié depuis 2023).

Apache .htaccess : bloc copier-coller pour en-têtes de sécurité

Ajoutez ceci en haut de votre .htaccess à la racine WordPress, au-dessus du bloc WordPress (# BEGIN WordPress). Le garde IfModule assure que le snippet ne plante pas si mod_headers est absent.

<IfModule mod_headers.c>
    # HSTS : forcer HTTPS pendant 1 an, inclure sous-domaines, preload-ready
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"

    # Prévenir le clickjacking
    Header always set X-Frame-Options "SAMEORIGIN"

    # Bloquer le MIME-sniffing
    Header always set X-Content-Type-Options "nosniff"

    # Limiter la fuite de referrer
    Header always set Referrer-Policy "strict-origin-when-cross-origin"

    # Désactiver les fonctionnalités navigateur non utilisées
    Header always set Permissions-Policy "camera=(), microphone=(), geolocation=(), interest-cohort=()"

    # Isolation cross-origin
    Header always set Cross-Origin-Opener-Policy "same-origin"

    # CSP de départ conservateur ; resserrer une fois que vous savez ce que votre site charge
    Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https:; style-src 'self' 'unsafe-inline' https:; img-src 'self' data: https:; font-src 'self' data: https:; connect-src 'self' https:; frame-ancestors 'self'; base-uri 'self'; form-action 'self';"
</IfModule>

Le mot-clé always est critique. Sans lui, les en-têtes ne sont envoyés que sur les réponses 2xx et 3xx ; avec lui, les pages d'erreur et redirections portent aussi les en-têtes. Sans always, un attaquant qui déclenche une erreur 500 voit une réponse non protégée.

Le module mod_headers doit être activé. Sur l'hébergement mutualisé, c'est généralement déjà le cas. Sur un Apache auto-géré : sudo a2enmod headers && sudo systemctl reload apache2.

Nginx : bloc copier-coller pour en-têtes de sécurité

Ajoutez ceci à l'intérieur du bloc server { ... } de votre site, typiquement dans /etc/nginx/sites-available/votresite.conf :

    # HSTS : forcer HTTPS pendant 1 an, inclure sous-domaines, preload-ready
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

    # Prévenir le clickjacking
    add_header X-Frame-Options "SAMEORIGIN" always;

    # Bloquer le MIME-sniffing
    add_header X-Content-Type-Options "nosniff" always;

    # Limiter la fuite de referrer
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;

    # Désactiver les fonctionnalités navigateur non utilisées
    add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), interest-cohort=()" always;

    # Isolation cross-origin
    add_header Cross-Origin-Opener-Policy "same-origin" always;

    # CSP de départ conservateur ; resserrer une fois que vous savez ce que votre site charge
    add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https:; style-src 'self' 'unsafe-inline' https:; img-src 'self' data: https:; font-src 'self' data: https:; connect-src 'self' https:; frame-ancestors 'self'; base-uri 'self'; form-action 'self';" always;

Le always en suffixe sur Nginx sert le même but qu'Apache : il fait s'appliquer l'en-tête aussi aux réponses d'erreur. Rechargez Nginx après le changement : sudo nginx -t && sudo systemctl reload nginx.

La règle des deux pièges de Nginx add_header

Nginx a une particularité qui pique régulièrement. Deux règles à intérioriser avant de toucher à la config de production :

  • add_header remplace, ne fusionne pas. Si vous définissez des en-têtes dans le bloc server et à nouveau dans un bloc location, les en-têtes du bloc location remplacent ceux du bloc server pour cet emplacement. Ils ne s'y ajoutent pas. Le symptôme : les en-têtes fonctionnent partout sauf dans un emplacement spécifique (comme /wp-admin/ où vous avez ajouté une règle custom).
  • Ajoutez toujours le flag always. Sans lui, une page 404 ou une page d'erreur 500 est servie sans vos en-têtes de sécurité. Les attaquants peuvent déclencher délibérément des erreurs pour contourner les protections basées sur les en-têtes.

Le Header always set d'Apache est l'équivalent du flag always de Nginx et a le même effet.

Apache vs Nginx : lequel est plus facile à configurer ?

Pratiquement équivalents pour les en-têtes de sécurité. Tous deux utilisent une seule directive par en-tête et acceptent des valeurs d'en-tête identiques. Trois différences à connaître :

  • Où vit la config. Apache via .htaccess peut être édité par répertoire par quiconque a un accès FTP à l'installation WordPress. La config Nginx vit hors de la racine du document et nécessite généralement SSH plus un reload. Pour l'hébergement WordPress mutualisé, .htaccess est plus pratique ; pour les setups Nginx managés, la config serveur est plus performante (Nginx ne relit pas les règles équivalentes à .htaccess à chaque requête, il garde la config nginx correcte en mémoire).
  • Overrides par location. Apache .htaccess hérite automatiquement des paramètres du répertoire parent. Les blocs location de Nginx nécessitent une re-déclaration explicite si vous en personnalisez un (à cause du piège de fusion ci-dessus).
  • Réalité de l'hébergement. La plupart des hébergements WordPress mutualisés (Hostinger, IONOS, GoDaddy, hôtes cPanel traditionnels) sont sur Apache. La plupart des hébergements WordPress managés (Kinsta, WP Engine, Raidboxes, SiteGround, Cloudways) sont sur Nginx. Le partage de marché est passé de majoritairement-Apache à environ 50/50 ces cinq dernières années.

Dois-je ajouter les en-têtes de sécurité dans WordPress plutôt que sur le serveur web ?

Vous pouvez, mais le niveau serveur web est meilleur. Trois options côté WordPress existent :

  • Plugin de sécurité (Wordfence, iThemes Security, etc.). A une fonctionnalité "en-têtes de sécurité" qui ajoute les mêmes en-têtes côté PHP. Fonctionne mais ajoute quelques millisecondes par requête. Utile si vous n'avez pas d'accès serveur web.
  • Code custom de plugin ou thème. Un petit mu-plugin peut appeler header() en PHP pour émettre chaque en-tête. Même overhead, mêmes mises en garde.
  • Config serveur web (recommandé). Zéro overhead PHP, s'applique à chaque réponse y compris erreurs 404 et fichiers statiques, survit aux plantages WordPress.

L'argument pour le niveau serveur web : les en-têtes ajoutés en PHP ne protègent pas les réponses qui contournent PHP. Si un attaquant atteint un fichier statique directement (un backup .phps oublié, un répertoire d'uploads avec des fichiers HTML), les en-têtes définis par PHP ne s'appliquent pas. Le serveur web voit chaque requête et est la bonne couche.

Comment ajuster la Content-Security-Policy sans casser mon site ?

CSP est l'en-tête de sécurité le plus impactant et aussi le plus susceptible de casser des choses. Un site WordPress charge des scripts et styles depuis des dizaines de sources par défaut : jQuery de /wp-includes, assets du thème, assets de plugins, Google Fonts (si non auto-hébergées), analytics, YouTube intégré, etc. Une CSP stricte qui ne whiteliste pas explicitement ces sources les bloquera et le site paraîtra cassé de manières subtiles (la connexion échoue, la galerie ne fonctionne pas, l'analytics s'arrête).

Le pattern de déploiement en deux phases qui fonctionne :

  1. Commencez en mode report-only. Utilisez Content-Security-Policy-Report-Only au lieu de Content-Security-Policy. Le navigateur ne bloque rien ; il journalise juste les violations dans la console développeur. Naviguez votre site pendant quelques jours, surveillez ce qui aurait été bloqué, et ajoutez les sources légitimes à votre politique.
  2. Passez en mode enforcing. Une fois que le mode report-only montre zéro violation sur une navigation normale, changez le nom de l'en-tête en Content-Security-Policy. Les violations sont maintenant bloquées.

Un piège courant : WordPress et beaucoup de plugins utilisent des gestionnaires d'événements JavaScript inline (onclick="") et des blocs <script> inline. Une CSP stricte requiert soit 'unsafe-inline' (annule la majeure partie de la protection) soit des nonces pour chaque script inline (changements de code significatifs). Le compromis pragmatique en 2026 : gardez 'unsafe-inline' pour l'instant, mais verrouillez les autres directives. Les futures versions WordPress vont vers des scripts inline compatibles avec les nonces.

Comment vérifier que mes en-têtes de sécurité fonctionnent ?

Quatre méthodes, du plus rapide au plus autoritatif :

  1. Rapport InspectWP. La section Sécurité liste chaque en-tête que votre site définit, sa valeur, et signale ceux manquants ou mal configurés. Un écran.
  2. curl en ligne de commande. curl -I https://votresite.com imprime les en-têtes de réponse. Cherchez les sept en-têtes ci-dessus ; vérifiez leurs valeurs.
  3. securityheaders.com. Un scanner public gratuit qui note votre site (A+ à F) et explique quels en-têtes manquent ou sont faibles. Standard de l'industrie pour les audits d'en-têtes.
  4. DevTools du navigateur. Ouvrez les DevTools (F12), onglet Network, cliquez sur la requête du document, regardez la section Response Headers. Utile pour voir les violations CSP en direct dans l'onglet Console.

Erreurs courantes et pièges

  • Ajouter HSTS sans confirmer que HTTPS fonctionne sur tout le site. HSTS force les navigateurs à utiliser HTTPS pendant un an. Si votre site a un certificat cassé ou une sous-page qui ne fonctionne qu'en HTTP, les utilisateurs sont verrouillés. Testez HTTPS à fond avant d'activer HSTS. Commencez avec un max-age court (comme 300 secondes) et montez jusqu'à un an.
  • Définir X-Frame-Options ET CSP frame-ancestors. Les deux fonctionnent mais frame-ancestors est l'équivalent moderne. Définir les deux est redondant mais inoffensif ; les navigateurs modernes préfèrent frame-ancestors.
  • Oublier includeSubDomains dans HSTS. Si votre site principal est HTTPS mais qu'un sous-domaine sert encore HTTP, les attaquants peuvent pivoter via le sous-domaine. includeSubDomains force HTTPS partout sous votre domaine. Vérifiez que tous les sous-domaines sont HTTPS avant d'ajouter ceci.
  • Copier une CSP depuis un tutoriel générique. Chaque site WordPress charge des assets tiers différents. Une CSP générique cassera votre site. Utilisez d'abord le mode report-only.
  • Mélanger en-têtes CDN et origine. Si vous avez Cloudflare devant, vous pouvez définir des en-têtes à Cloudflare (Page Rules ou Transform Rules) ou à l'origine. Définir les deux avec des valeurs différentes cause de la confusion en débogage. Choisissez un endroit et documentez-le.
  • Oublier de recharger après édition. Les changements Nginx ne font rien jusqu'à systemctl reload nginx. Les changements .htaccess d'Apache sont instantanés ; les changements de la config principale Apache nécessitent un reload.

Et HTTP/3 et l'histoire moderne des en-têtes ?

HTTP/3 ne change rien à propos des en-têtes à définir ; la sémantique des en-têtes est identique à travers HTTP/1.1, HTTP/2 et HTTP/3. Un en-tête qui devient pertinent en HTTP/3 est Alt-Svc, qui annonce la disponibilité de HTTP/3 aux clients arrivés en HTTP/2. La plupart des serveurs web l'ajoutent automatiquement.

Le paysage navigateur évolue aussi graduellement vers l'application de défauts modernes même quand les en-têtes manquent. Chrome et Firefox utilisent maintenant par défaut strict-origin-when-cross-origin pour Referrer-Policy si aucun en-tête n'est envoyé, et supposent de plus en plus HTTPS pour tout site qui a été servi un jour en HTTPS. Définir les en-têtes explicitement reste recommandé parce que les défauts varient selon la version du navigateur et parce que les clients HTTP non-navigateur (curl, scripts, outils de monitoring) n'implémentent pas ces défauts.

Ce que vérifie InspectWP

La section Sécurité de chaque rapport InspectWP inspecte les en-têtes de réponse de votre document principal et signale lesquels des en-têtes de sécurité standard sont présents, quelles sont leurs valeurs, et lesquels manquent ou sont définis à des valeurs non recommandées. HSTS manquant sur un site HTTPS est signalé en avertissement ; X-Content-Type-Options manquant est signalé en informatif ; une CSP définie à default-src * (effectivement aucune politique du tout) est signalée comme mauvaise configuration. Le rapport note aussi quand les en-têtes sont définis au niveau CDN versus au niveau origine, puisque cela affecte ce que vous devriez changer pour les mettre à jour. L'état recommandé est les sept en-têtes présents avec des valeurs raisonnables, et CSP soit en mode report-only pendant que vous l'ajustez, soit en mode enforcing une fois ajustée.

Vérifiez votre site WordPress dès maintenant

InspectWP analyse votre site WordPress pour détecter les problèmes de sécurité, de SEO, de conformité RGPD et de performance — gratuitement.

Analyser votre site gratuitement