Les en-têtes de sécurité ne sont pas la solution magique au piratage. Ils ne colmateront pas une faille applicative ou un plugin compromis. En revanche, ils réduisent nettement la surface d’attaque côté navigateur, ralentissent certaines classes d’abus et donnent un cadre plus strict à ce que votre site est autorisé à faire.
Sur WordPress, le sujet devient vite concret parce que vous cumulez plusieurs couches: serveur web (Apache ou Nginx), éventuel CDN, reverse proxy, plugin de cache, réseau multisites, et parfois des thèmes qui injectent des scripts depuis des domaines externes. Les en-têtes “simples” passent facilement, les politiques plus strictes (notamment CSP) demandent du réglage. Le bon réflexe consiste à viser le bon niveau de contrainte, au bon moment, et à tester avant de “verrouiller”.
Ce que les en-têtes changent vraiment (et ce qu’ils ne changent pas)
Un en-tête de sécurité, c’est une instruction envoyée au navigateur. Le navigateur l’applique sur vos pages pour limiter des comportements: chargement de ressources depuis des origines précises, exécution de scripts inline, affichage en iframe, type MIME accepté, durée d’envoi sur HTTPS, etc.
La confusion classique, que j’ai déjà vue sur des sites en production, c’est de penser que “mettre des en-têtes” suffit à se protéger. En pratique, un en-tête n’empêche pas un attaquant d’exploiter une vulnérabilité côté serveur. Il peut par contre empêcher qu’une injection de code aboutisse à une exécution réussie, ou empêcher le chargement de scripts non autorisés.
C’est aussi un sujet d’hygiène: des en-têtes cohérents évitent que différents composants (CDN, plugin, serveur) se contredisent. Quand deux sources envoient des politiques différentes, les navigateurs choisissent souvent la dernière, ou ignorent selon les cas. Résultat: vous ne savez plus ce qui est réellement appliqué.
Les en-têtes essentiels à connaître sur WordPress
Vous pouvez regrouper les en-têtes utiles en plusieurs familles, parce que leur rôle est distinct.
HSTS (Strict-Transport-Security)
HSTS indique au navigateur de ne jamais revenir à HTTP tant que la durée n’expire pas. C’est l’un des en-têtes les plus bénéfiques, surtout si vous avez déjà des redirections correctes. Le piège, c’est la mauvaise configuration initiale: si votre HTTPS n’est pas stable, vous pouvez “verrouiller” des visiteurs sur un canal cassé.
Dans les réglages HSTS, deux paramètres importent: max-age et parfois includeSubDomains et preload. preload n’est pertinent que si votre domaine et sa configuration répondent aux critères du navigateur. Beaucoup de sites commencent avec un max-age modéré, puis augmentent après stabilité.
X-Frame-Options (ou la modernisation via CSP frame-ancestors)
L’objectif est d’éviter l’affichage du site dans une iframe sur un domaine non autorisé, ce qui aide contre le clickjacking. On rencontre encore X-Frame-Options: DENY ou SAMEORIGIN, mais une CSP bien écrite avec frame-ancestors fait souvent mieux, car elle s’intègre à une politique globale.
Le trade-off se voit vite sur WordPress: certains plugins de traduction, de chat, ou de médias peuvent s’appuyer sur des iframes. Si vous bloquez trop, vous cassez des fonctionnalités. Là encore, il faut tester.
X-Content-Type-Options
Cet en-tête limite une vieille classe de confusion MIME. Avec nosniff, le navigateur évite de “deviner” le type de contenu à partir de l’en-tête déclaré. Sur WordPress, c’est particulièrement utile si des fichiers statiques passent par des chemins d’accès parfois atypiques (rewrite, cache, CDN).
X-XSS-Protection
Il s’agit d’un en-tête historique, surtout utile pour certains navigateurs plus anciens. Aujourd’hui, l’essentiel de la protection contre XSS passe par une CSP correcte et par le durcissement applicatif. Donc, je le traite comme un “bonus” plutôt qu’un pilier.
Referrer-Policy
Quand vous envoyez des visiteurs vers des domaines tiers (analytics, widgets, intégrations), le navigateur contrôle la quantité d’informations de provenance. strict-origin-when-cross-origin est un compromis fréquent: vous gardez l’essentiel sans exposer systématiquement le chemin.
Permissions-Policy (et son évolution)
Cet en-tête détermine si votre page autorise des API navigateur sensibles (caméra, micro, géolocalisation, etc.). C’est discret, mais efficace pour réduire l’impact d’une injection. Le piège, c’est la compatibilité: selon vos fonctionnalités (par exemple un player vidéo avec géolocalisation ou un widget), vous devrez ajuster.
CSP (Content-Security-Policy), le plus puissant et le plus délicat
La CSP est la plus “structurante” et souvent la plus source de casses si vous l’activez trop tôt, trop restrictif. Elle peut limiter:
- où le navigateur charge les scripts, styles, images, polices l’exécution des scripts inline les capacités des formulaires ou des ressources via connect-src, img-src, frame-src, etc. le placement de la page dans des iframes via frame-ancestors
Sur WordPress, la difficulté vient de l’écosystème: CDN de thème, Google Fonts, scripts de tags marketing, plugins qui ajoutent des bibliothèques, parfois des scripts inline côté thème. La bonne approche consiste à commencer par une CSP “en mode rapport” ou une CSP partielle, puis à renforcer.
Où configurer ces en-têtes sur WordPress : serveur, .htaccess, plugin, CDN
Le point le plus important, c’est l’emplacement. Sur WordPress, vous pouvez définir des en-têtes:
- au niveau du serveur web (Apache ou Nginx) via un fichier .htaccess (Apache) via votre plugin de sécurité ou un plugin de performance via un CDN ou un reverse proxy
Le risque majeur, c’est la duplication ou la contradiction. Par exemple, un plugin peut envoyer X-Frame-Options: SAMEORIGIN, pendant que votre serveur envoie DENY. Dans la pratique, certains navigateurs suivent la première ou la dernière occurrence, mais vous ne devez pas compter là-dessus. Je privilégie un seul point de vérité, puis j’observe ce que le navigateur reçoit réellement.
Cas Apache avec .htaccess
Si votre site tourne sous Apache, beaucoup de guides proposent d’ajouter des règles dans .htaccess. Ça peut fonctionner, mais attention à l’ordre et aux directives déjà présentes. Voici un exemple minimaliste et raisonnable pour démarrer, sans forcer une CSP complète:
Header always set X-Content-Type-Options "nosniff" Header always set Referrer-Policy "strict-origin-when-cross-origin" Header always set X-Frame-Options "SAMEORIGIN" Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()" # HSTS: à adapter après validation HTTPS stable Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"Le SAMEORIGIN suppose que vous ne voulez pas d’intégration dans des iframes depuis d’autres origines. Si vous avez besoin d’intégrations, vous ajustez.
Pour HSTS, je préfère ne pas mettre includeSubDomains dès le premier jour si vous n’êtes pas sûr de tous les sous-domaines. Une erreur peut vous compliquer la vie pendant longtemps.
Cas Nginx
Sous Nginx, la logique est similaire, mais la syntaxe change. Exemple de bloc conceptuel dans la configuration du site:
Add_header X-Content-Type-Options "nosniff" always; Add_header Referrer-Policy "strict-origin-when-cross-origin" always; Add_header X-Frame-Options "SAMEORIGIN" always; Add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always; Add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;Sur Nginx, selon votre configuration, vous devez parfois ajouter l’en-tête dans plusieurs blocs (http, server, location). Là encore, l’observation en navigateur prime sur la théorie.
Si vous utilisez un CDN (Cloudflare, Fastly, etc.)
Quand un CDN est en jeu, l’en-tête peut être injecté au niveau du proxy, et votre serveur peut ne pas être la source finale. Sur certains setups, le CDN met déjà des en-têtes par défaut, ou vous permet de les configurer. Dans ce cas, la meilleure stratégie est de: 1) identifier la source réelle des en-têtes reçus 2) centraliser la configuration au même endroit
Ce que j’ai vu plusieurs fois: un site avec un plugin “sécurité” envoie X-Frame-Options, mais le CDN ajoute une CSP différente. Le navigateur applique une version, et l’équipe croit que le plugin est “coupable” alors que c’est le proxy.
CSP sur WordPress : comment éviter le casse immédiat
La CSP peut devenir un cauchemar si elle est trop rigide sans tenir compte des scripts inline et des domaines tiers. La bonne approche dépend du niveau de contrôle que vous avez sur le contenu rendu.
Une CSP en mode rapport pour commencer
La directive Content-Security-Policy-Report-Only permet de tester sans bloquer. Le navigateur enverra les violations à un endpoint de rapport (selon votre paramétrage). Cela réduit énormément la probabilité de casser un menu, un formulaire ou un plugin.
Ensuite, une fois que vous avez identifié les domaines nécessaires, vous passez en CSP enforce, avec une directive stricte.
Sur WordPress, surtout si vous utilisez des plugins de scripts marketing (pixels, tags), vous allez probablement itérer plusieurs fois. Ce n’est pas un échec, c’est la démarche normale.
Exemples de CSP progressives
Je vais rester volontairement généraliste, parce qu’une CSP dépend de vos plugins et de vos domaines. Une CSP trop “jolie sur papier” est souvent celle qui casse votre site.
Une première étape pragmatique consiste à limiter les sources de scripts tout en acceptant temporairement les inline si le thème les utilise (via unsafe-inline ou via nonce, selon votre stratégie). Le but n’est pas d’être parfait dès J1, c’est d’obtenir une baseline.
Exemple de structure (à adapter):
Content-Security-Policy: Default-src 'self'; Script-src 'self' 'unsafe-inline' https://www.googletagmanager.com https://www.google-analytics.com; Style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; Img-src 'self' data: https:; Font-src 'self' https://fonts.gstatic.com; Connect-src 'self' https://www.google-analytics.com; Frame-ancestors 'self';Même dans cet exemple, le point fragile est 'unsafe-inline'. Si vos scripts peuvent passer par des nonces ou si vos thèmes/plugins peuvent être ajustés, c’est préférable. Mais quand on a un WordPress “mélangé” avec beaucoup de code déjà en place, entrer directement en mode nonce-only sans plan peut casser des choses.
Les scripts inline dans WordPress, le vrai sujet
De nombreux thèmes utilisent des scripts inline pour des configurations et des petites aides. Certains plugins insèrent aussi des bouts inline. Si votre CSP interdit l’inline, ces scripts ne s’exécutent plus, et l’apparence ou la navigation devient bancale.
Les deux voies réalistes que j’ai rencontrées:
- soit vous acceptez l’inline temporairement, le temps de cartographier soit vous rendez l’environnement compatible nonce, ce qui demande un minimum de contrôle côté génération des pages
Le plus souvent, l’option “temporiser” est plus efficace en phase initiale, puis on renforce.
frame-ancestors et clickjacking
Pour empêcher l’affichage dans une iframe, frame-ancestors est la directive CSP moderne. Vous pouvez remplacer ou compléter X-Frame-Options. Le choix dépend de votre politique globale, et de la cohérence recherchée.
Sur un site WordPress normal, limiter à frame-ancestors 'self' est un bon point de départ. Mais si vous utilisez une intégration dans un autre système (portail client, intégration partenaire), il faut ajuster à des origines autorisées.
Les en-têtes cookies, le complément indispensable (même si vous ne les appelez pas “en-têtes de sécurité”)
Même si la question porte sur les en-têtes HTTP, sur WordPress la partie qui compte vraiment dans la réduction de l’impact d’un incident concerne aussi les cookies: HttpOnly, Secure, SameSite.
WordPress gère déjà une bonne partie de cela, mais selon votre configuration HTTPS, votre reverse proxy, et parfois des paramètres de migration, vous pouvez vous retrouver avec des cookies qui ne portent pas les bons attributs. Ça se voit dans les devtools, pas dans les suppositions.
Si vous avez un environnement en reverse proxy avec TLS terminé côté proxy, WordPress doit être correctement informé du schéma (sinon il peut marquer des cookies sans Secure). Dans ce cas, votre durcissement “en-têtes” HTTP perd une partie de son intérêt, parce que les cookies restent plus exposés que nécessaire.
Tester comme il faut, pas comme on peut
Les en-têtes se testent à deux niveaux:
- ce que vous pensez envoyer (configuration) ce que le navigateur reçoit vraiment (réponse HTTP finale)
Un site peut “changer de comportement” selon la page, la présence d’un cache, ou la négociation de règles CDN. Il faut donc vérifier sur des pages représentatives: une page publique, une page avec formulaires, une page qui charge des scripts tiers, une page de connexion.
Voici la checklist que j’utilise dans les déploiements quand on renforce des politiques:

- Vérifier les en-têtes sur la réponse HTTP réelle dans les devtools (onglet Network), pas sur un test théorique Tester avec un navigateur propre (profil sans extensions), pour éviter les biais d’extensions qui changent les scripts Contrôler les pages avec plugins sensibles, notamment formulaires, recherche et intégrations tierces Mettre en place une CSP en “report only” si vous ne maîtrisez pas encore les scripts injectés Suivre les erreurs console, erreurs CSP incluses, car c’est là que le site casse le plus souvent
Cette démarche évite le classique “ça marche sur ma page d’accueil” alors que la page de contact ou le checkout échoue.
Quand ça casse: scénarios fréquents et réponses concrètes
Le problème n’est pas de tomber sur une erreur, c’est de ne pas savoir ce qui l’a déclenchée. Quelques scénarios reviennent souvent.
Les scripts Google et tags marketing
Dès qu’on met CSP, des scripts distants se retrouvent bloqués, ce qui coupe analytics, tags et parfois des composants UI. La console affiche une erreur liée à script-src ou connect-src. On https://gardewp.fr/securite-wordpress/ corrige en ajoutant les origines réellement utilisées.
Point important: ne pas ajouter tous les domaines “au hasard”. Ajoutez seulement ceux nécessaires, sinon vous créez une politique large qui perd son intérêt.
Les polices et le chargement des fonts
Quand font-src est trop strict, le site charge des fallback au lieu des polices. C’est un bug visuel plutôt qu’un bug fonctionnel, mais sur certains thèmes c’est visible immédiatement.
Souvent, les polices viennent de Google Fonts, parfois d’un CDN interne au thème. Il faut ajuster font-src et parfois style-src si les feuilles de style sont externes.
L’intégration dans des iframes
Sur WordPress, si vous avez un “embedding” de pages (ou un partenaire qui intègre votre contenu), X-Frame-Options ou frame-ancestors peut bloquer. Dans ce cas, je préfère passer par une politique CSP ciblée, avec des origines autorisées, plutôt que d’abandonner toute protection.
Les plugins de formulaires et d’anti-spam
Certains anti-spam chargent des scripts externes, ou font du fetch vers des endpoints tiers. Si connect-src n’inclut pas ces domaines, l’expérience se dégrade: CAPTCHA qui ne charge pas, soumission qui échoue, ou feedback incohérent.
Une stratégie utile consiste à décliner connect-src avec parcimonie et à valider sur la page concernée. Si un plugin change d’endpoint après mise à jour, il faudra réajuster.
Une politique d’en-têtes “raisonnable” à prioriser
Si vous devez avancer par étapes, je recommande de prioriser ce qui apporte le plus de gain avec le moins de risque, puis d’attaquer la CSP de manière structurée.
Voici une priorisation courte, issue de ce que j’ai vu fonctionner sur des WordPress classiques:
- X-Content-Type-Options: nosniff Referrer-Policy: strict-origin-when-cross-origin (ou variante adaptée) X-Frame-Options ou frame-ancestors dans CSP, selon votre stratégie Permissions-Policy avec un périmètre minimal (souvent caméras, micro, géolocalisation) HSTS une fois HTTPS validé sur tout le périmètre
La CSP arrive ensuite, ou en parallèle si vous travaillez en itération avec report-only. La CSP “en un coup” marche rarement sur un WordPress vivant.
Points de vigilance spécifiques aux environnements WordPress
Caching et compression
Un cache peut servir une version d’en-têtes moins récente. Exemple typique: plugin de cache qui stocke la réponse avant mise à jour des règles. Résultat, vos tests “refont surface” plus tard alors que votre configuration a été corrigée.
La solution n’est pas de deviner, mais de tester sur un chemin qui bypass le cache, ou de purger correctement. Pensez aussi aux en-têtes ajoutés différemment entre pages HTML, fichiers statiques, et endpoints.
WordPress multisite
Sur multisite, des sites peuvent partager la même instance serveur mais avoir des configurations différentes: domaines, sous-domaines, redirections. HSTS et policies de frame peuvent toucher l’ensemble si vous utilisez includeSubDomains. Il faut donc valider la cohérence multi-sites, sinon vous appliquez une contrainte là où elle ne devrait pas s’appliquer.
Redirections HTTP vers HTTPS et boucle de confiance
Avant d’activer HSTS, vérifiez que toutes les routes finissent bien en HTTPS, y compris pour:
- les pages avec paramètres les URLs avec ou sans trailing slash les sous-domaines utilisés pour des services
Une fois HSTS activé avec un max-age long, vous ne pouvez plus compter sur la correction immédiate côté serveur pour certains visiteurs.
Mettre en place sans se piéger : une méthode d’approche en trois mouvements
Je conseille une approche “durcissement par paliers”, pas une liste de tout ajouter d’un coup.
D’abord, ajoutez des en-têtes peu risqués (nosniff, referrer policy, une protection clickjacking cohérente, permissions policy minimaliste). Ensuite, validez sur plusieurs pages et plusieurs navigateurs.
Ensuite, jouez la carte CSP progressivement. Commencez par une CSP en report-only pour observer les domaines et les catégories bloquées. Une fois que vous avez une CSP enforce stable sur les pages critiques, vous pouvez renforcer les directives qui bloquent l’inline et resserrer les script-src.
Enfin, seulement quand le HTTPS est solide partout, vous augmentez HSTS ou vous ajoutez des paramètres plus agressifs.
Ce rythme évite le piège le plus coûteux: revenir en arrière tard, en doublant les changements, et en perdant le fil entre l’origine de la casse et la politique fautive.
Ce que vous gagnerez en pratique
Les bénéfices ne se voient pas uniquement dans des “scores” de sécurité. Ils se ressentent:
- dans la réduction de certaines exploitations côté navigateur dans la stabilité du site quand vous retirez progressivement des permissivités inutiles dans la capacité à diagnostiquer un problème via les erreurs console CSP et les refus de chargement
Et surtout, vous passez d’une sécurité “déclarée” à une sécurité “mesurée”, car vous testez réellement ce que le navigateur reçoit.
Si vous voulez un point de départ concret
Si vous me donnez votre configuration (Apache ou Nginx), la présence d’un CDN, vos plugins principaux (notamment ceux qui injectent des scripts), et les domaines tiers utilisés (analytics, polices, widgets), je peux vous proposer une base de politiques cohérentes, avec une CSP réaliste pour un premier palier. L’objectif reste le même: obtenir un durcissement qui protège, sans casser les pages que vos visiteurs utilisent tous les jours.