Sécuriser WordPress : configurer CSP (Content Security Policy)

Quand on parle de durcissement d’un site WordPress, on pense vite à “changer les mots de passe” et “mettre à jour les plugins”. C’est indispensable, mais ça ne suffit pas à lui seul. Une partie des attaques modernes vise précisément votre capacité à empêcher le navigateur d’exécuter du code injecté. C’est là que la CSP (Content Security Policy) devient un outil très concret.

La CSP n’est pas une recette miracle. Elle demande de réfléchir à ce que votre site charge réellement, à partir de quelles origines, et comment WordPress et vos plugins fonctionnent dans votre configuration. Par contre, bien réglée, elle réduit fortement l’impact d’une injection de script, même si un plugin devient vulnérable, ou si un attaquant arrive à déposer un contenu malveillant dans une publication.

Dans cet article, je vais vous guider pour configurer une CSP sur un site WordPress, avec une approche pragmatique: d’abord comprendre ce que vous voulez autoriser, ensuite déployer en mode observation, puis verrouiller progressivement. Je parlerai aussi des pièges fréquents, notamment avec les thèmes, les éditeurs de contenu, les “cookies consent”, et certains scripts “inline” que personne n’a envie de supprimer du jour au lendemain.

CSP en clair, sans jargon inutile

La CSP est une politique HTTP que vous envoyez au navigateur. Elle dicte quels types de ressources peuvent être chargés et exécutés, et depuis quelles sources. Concrètement, vous pouvez dire par exemple:

    le navigateur peut charger des scripts uniquement depuis votre domaine et éventuellement quelques services précis les feuilles de style doivent venir de certaines origines l’exécution de code inline doit être refusée le navigateur doit refuser les scripts qui ne matchent pas les règles

L’intérêt est immédiat: si un attaquant injecte une balise

La difficulté, elle, tient à un détail: sur WordPress, les scripts et styles viennent parfois de plusieurs endroits, parfois en inline, parfois via des balises générées par le thème, parfois via des plugins. Une CSP trop stricte au départ peut casser des fonctionnalités légitimes. C’est pour cela qu’on préfère déployer en plusieurs étapes.

Pourquoi WordPress rend la CSP “vivante”

WordPress est un système modulaire. Le noyau charge une base, mais ensuite tout dépend de votre thème et de vos plugins. Certains plugins injectent du JavaScript inline, d’autres ajoutent des scripts externes, d’autres encore utilisent des “data:” ou des fontes à des endroits spécifiques.

Même si vous avez l’habitude de sécuriser WordPress, vous pouvez vous retrouver face à ces situations:

    un thème ajoute des scripts inline pour des effets UI, sliders, animations un plugin de tracking ajoute des scripts depuis plusieurs domaines (réseaux sociaux, analytics, pixel) un plugin de consentement (RGPD) retarde l’initialisation de scripts jusqu’à l’acceptation un plugin de galerie ou de formulaires charge des ressources depuis des CDN, parfois avec des chemins variables un éditeur (Gutenberg) ou un bloc “custom HTML” peut produire des éléments que vous n’anticipiez pas

CSP doit donc refléter la réalité de votre site. La bonne nouvelle, c’est que cette réalité se mesure. Les navigateurs vous donnent des logs quand une ressource est refusée, à condition de démarrer proprement.

Choisir une stratégie: rapport d’abord, blocage ensuite

La méthode la plus efficace que j’ai vue sur des projets réels consiste à commencer par une CSP en mode rapport seulement, puis à passer en mode enforcement (blocage). Historiquement, on utilisait surtout report-uri. Aujourd’hui, la directive recommandée pour la plupart des contextes est report-to ou des endpoints compatibles, mais selon votre stack, le support peut varier.

En pratique, la façon la plus simple est de déployer d’abord une directive qui envoie les violations vers un endpoint de log. Vous pouvez ensuite observer dans les outils du navigateur et corriger les règles.

L’idée est simple: vous ne cherchez pas à “deviner” toutes les sources autorisées au premier coup. Vous cherchez à documenter le comportement actuel, puis vous réduisez le champ progressivement.

Les directives CSP à connaître pour WordPress

Je vais rester concret. Une CSP utile pour un site WordPress contient souvent plusieurs directives, chacune visant un type de contenu:

    default-src: source par défaut quand une autre directive ne s’applique pas script-src: autorise les scripts, c’est la plus critique style-src: gère les CSS img-src: gère les images font-src: gère les polices connect-src: contrôle les appels réseau (fetch, xhr, websockets) frame-src: contrôle les contenus embarqués en iframe object-src: limite les objets (souvent inutile sur WordPress moderne) base-uri: contrôle l’URI de base pour les pages form-action: contrôle où les formulaires peuvent soumettre upgrade-insecure-requests: force les requêtes HTTP vers HTTPS

Sur un site WordPress standard, script-src et style-src posent le plus de questions, car beaucoup de thèmes et plugins utilisent encore du inline, ou des scripts générés côté serveur.

Exemple de politique de départ (prudente)

Voici une CSP “de travail” qui sert souvent de point de départ pour un site WordPress, en cherchant à éviter de tout casser. Le but n’est pas de la copier telle quelle sans vérification, mais de comprendre la logique.

Une politique typique de base ressemble à ceci (je l’écris en une seule ligne pour la lisibilité en contexte, mais vous l’utiliserez telle quelle dans l’en-tête):

Content-Security-Policy: default-src 'self' https: data:; script-src 'self' 'unsafe-inline' https:; style-src 'self' 'unsafe-inline' https:; img-src 'self' data: https:; font-src 'self' https: data:; connect-src 'self' https:; frame-src 'self' https:; object-src 'none'; base-uri 'self'; form-action 'self'

Ce que j’accepte ici au départ, c’est volontairement plus large que ce qu’on viserait à la fin. En particulier, unsafe-inline (pour scripts et styles) réduit la protection, mais évite de casser le site. Ensuite, vous supprimez progressivement ces permissifs.

Si votre site ne charge pas de ressources en data:, vous pouvez retirer data:. Si vos polices viennent uniquement de votre domaine ou d’un CDN spécifique, vous restreignez.

Notez aussi object-src 'none', qui est généralement sain. WordPress n’a pas besoin d’objets type Flash ou encombrants dans la plupart des cas.

Déployer CSP sur WordPress: où placer l’en-tête

Il y a plusieurs voies. Le bon choix dépend de votre hébergement.

Option 1: via le serveur (recommandé)

Si vous contrôlez Nginx ou Apache, vous pouvez définir l’en-tête CSP dans la configuration du site. C’est propre, performant, et cohérent sur l’ensemble du site.

Exemple Nginx (schéma indicatif): vous définissez add_header Content-Security-Policy "..."; dans le bloc serveur, avec always selon vos besoins.

Cette option est idéale si vous avez aussi d’autres en-têtes de sécurité (HSTS, X-Content-Type-Options, etc.) Et que vous voulez une gouvernance centralisée.

Option 2: via un plugin WordPress

Il existe des plugins qui ajoutent une CSP via hooks WordPress. C’est pratique quand vous n’avez pas accès à la configuration serveur, ou quand vous voulez itérer rapidement.

Attention toutefois à deux choses: certains plugins appliquent CSP à certaines pages seulement, ou n’envoient pas l’en-tête exactement comme attendu pour toutes les routes. Et si vous avez un cache (page cache, reverse proxy), vous pouvez vous retrouver avec une CSP qui n’est pas mise à jour immédiatement. Dans ce cas, désactivez le cache le temps de tester.

Option 3: via un CDN ou un WAF

Si votre site passe par Cloudflare, un reverse proxy, ou un WAF, vous pouvez configurer la CSP au niveau “edge”. C’est souvent efficace, mais demande de vérifier que la CSP n’est pas doublonnée ou contradictoire avec celle envoyée par WordPress.

Dans tous les cas, la règle d’or reste la même: vérifiez l’en-tête final reçu par le navigateur, pas ce que vous avez configuré.

Procédure que j’utilise en mission: observation, corrections, verrouillage

Voici une méthode qui évite les “surprises de minuit” après une mise en production.

Commencez en “rapport seulement” Déployez sur une zone de test ou sur un environnement de staging Ouvrez vos pages clés et utilisez la navigation réelle (accueil, page produit, formulaires, pages de consentement) Regardez les violations dans la console et dans la collecte de rapports Ajustez les sources autorisées, puis repassez en mode bloquant progressivement

Si vous n’avez pas de staging, faites au moins un test sur votre page la plus exposée, puis attendez un cycle complet de navigation, y compris sur mobile.

Vérifier ce que le navigateur reçoit vraiment

Avant d’affiner la politique, il faut valider le diagnostic. Sur chaque navigateur, ouvrez “Outils développeur”, vérifiez l’onglet réseau, et cherchez l’en-tête Content-Security-Policy.

C’est aussi le moment de vérifier des détails qui font gagner beaucoup de temps:

    la CSP est-elle unique ou dupliquée? le header est-il le même sur toutes les pages? les directives contiennent-elles les bonnes sources (avec ou sans guillemets) est-ce que votre cache retarde l’application

Une CSP dupliquée peut créer un comportement déroutant, car plusieurs en-têtes peuvent se combiner, ou le navigateur peut utiliser l’une d’elles selon la manière dont c’est fourni.

Le vrai nœud: gérer les scripts inline

Les deux directives qui font mal dans WordPress, c’est souvent script-src et style-src, car les inline peuvent être utilisés par:

    des thèmes des plugins qui injectent des configurations via window... des blocs HTML ou contenus personnalisés

Vous aurez deux approches.

Approche A: vous commencez avec unsafe-inline pour ne pas casser, puis vous réduisez. C’est le chemin le plus sûr quand vous n’avez pas le contrôle total sur tout le code généré.

Approche B: vous passez à un mode “plus strict” avec des nonces ou des hash. Les nonces permettent d’autoriser des scripts inline seulement s’ils portent une valeur spécifique, mais cela demande que le serveur injecte la nonce dans chaque script inline au moment où il est généré. Sur WordPress, ça peut exiger une intégration plus fine côté thème/plugin.

Dans la pratique, sur un site WordPress avec de nombreux plugins, l’approche A donne des résultats rapides, puis vous progressez sur les pages et plugins qui posent problème, au fur et à mesure que vous migrez vers des pratiques moins dépendantes de l’inline.

Une checklist pragmatique pour éviter les cassures

Voici les points à contrôler avant de passer en blocage sur vos pages de production.

    Vérifiez les pages où vous avez des formulaires, car l’envoi peut dépendre de form-action ou de connect-src Testez les pages avec des iframes (vidéos intégrées, cartes, contenus distants) et ajustez frame-src si nécessaire Confirmez que les scripts de vos plugins essentiels (cache, galerie, consentement) ne sont pas refusés Si vous utilisez un CDN pour les assets, ajoutez explicitement les domaines de ce CDN dans les directives concernées Assurez-vous que votre politique ne contient pas de valeurs trop permissives qui resteraient après “stabilisation”

Cette checklist ne remplace pas les tests réels, mais elle évite déjà les erreurs classiques.

Pièges fréquents avec les plugins WordPress

Après avoir déployé CSP plusieurs fois sur des sites WordPress, voici ce qui revient le plus, souvent sans qu’on y pense au départ.

image

Première surprise: les scripts “dynamiques” ajoutés par des plugins. Quand un plugin charge un script après acceptation RGPD, le navigateur appliquera toujours la CSP. Si la source n’est pas autorisée dans script-src, il ne se passera rien, sans explication côté serveur.

image

Deuxième surprise: les appels API. Les formulaires WordPress modernes, les plugins de recherche, ou certains scripts d’optimisation peuvent utiliser fetch vers un domaine tiers. Si ce domaine n’est pas dans connect-src, vous aurez des erreurs JavaScript difficiles à diagnostiquer.

Troisième surprise: les images et les polices. On pense rarement à font-src. Si votre thème charge des polices depuis un CDN, la page peut rester “fonctionnelle”, mais la mise en forme sera cassée, ou le chargement sera silencieusement refusé.

Voici les cas qui demandent le plus souvent des ajustements:

    intégration de vidéos ou contenus via iframe scripts analytics ou pixels publicitaires widgets sociaux, commentaires, embeds optimisateurs d’images qui chargent des scripts spécifiques formulaires tiers qui envoient vers des endpoints externes

La règle, dans tous les cas, est la même: observez les violations, identifiez la ressource refusée, puis autorisez la source minimale nécessaire.

Étape suivante: supprimer progressivement les “portes ouvertes”

Une fois que tout fonctionne en mode “rapport” ou en enforcement avec des permissifs, vous pouvez serrer la vis.

Le mouvement le plus classique consiste à:

1) réduire unsafe-inline 2) restreindre script-src et style-src au strict nécessaire 3) remplacer des autorisations larges par des domaines précis 4) supprimer data: si vous n’avez pas besoin de charger des images ou polices depuis data URIs

Soyez réaliste: parfois, supprimer l’inline demande du travail dans le thème ou dans les plugins. Si un plugin injecte du JavaScript inline de manière indispensable, la solution peut être d’utiliser une version plus récente du plugin, une option de configuration qui externalise les scripts, ou de remplacer le plugin par une alternative mieux compatible.

Le compromis est souvent le suivant: on garde temporairement une partie permissive le temps de faire évoluer l’écosystème.

Adapter la CSP à votre mode de rendu et à votre cache

Un point qui surprend quand on configure CSP pour la première fois: la page peut être servie par un cache, et la CSP peut ne pas se mettre à jour comme prévu.

Sur WordPress, vous pouvez avoir un cache de page, un plugin de minification, et parfois un reverse proxy. Si votre CSP change, assurez-vous que:

    le header est recalculé ou non mis en cache de manière incorrecte le cache est purgé au moment du déploiement vos pages tests ne sont pas servies depuis une ancienne version

Quand une CSP échoue “par intermittence”, c’est souvent un indice de cache ou de double politique appliquée.

CSP et sécurité au quotidien: ce que CSP améliore, ce qu’elle ne remplace pas

CSP est une barrière au niveau du navigateur. Elle aide beaucoup contre l’exécution de scripts injectés. Mais elle ne remplace pas:

    une authentification solide (et surtout des sessions bien gérées) la limitation des autorisations WordPress la mise à jour régulière des plugins et thèmes la validation du contenu côté serveur (là où elle a du sens) la protection contre les attaques de type brute force, voire une limitation du rate

J’insiste souvent là-dessus, parce que la CSP donne un sentiment de “verrouillage complet”. En réalité, elle protège surtout contre certains scénarios d’injection. Les autres types d’attaques exigent d’autres couches.

Exemple de déploiement progressif (sans casser tout)

Imaginons un site WordPress qui utilise:

    un thème qui ajoute du JavaScript inline pour un menu un plugin analytics chargé depuis un ou deux domaines un plugin consentement avec des scripts conditionnels une police depuis un CDN des images depuis le domaine du site et un CDN

Vous pouvez commencer par une politique large, puis resserrer en fonction des refus réels.

Au début, vous mettez script-src 'self' 'unsafe-inline' https: et style-src 'self' 'unsafe-inline' https:. Une fois que les pages clés fonctionnent, vous regardez les violations. Si GardeWP spécialiste sécurité WordPress les erreurs ne concernent que certains scripts tiers, vous ajoutez des domaines précis et vous réduisez l’ensemble.

Quand vous voyez que tout ce qui est inline est strictement nécessaire sur une page, vous pouvez envisager de passer au nonce sur cette zone, plutôt que d’essayer de tout convertir d’un coup. C’est plus lent, mais plus réaliste, surtout si plusieurs plugins sont impliqués.

Limites et décisions difficiles

Il y a des cas où CSP devient plus coûteuse que ce que l’équipe veut absorber à court terme. Par exemple:

    un thème ou un plugin qui dépend massivement d’inline et de styles inline sans option d’externalisation une logique de pages générées très dynamiquement, avec des scripts inline difficilement ajustables un parc d’hébergement hétérogène où certaines routes n’appliquent pas l’en-tête de manière uniforme

Dans ces situations, le bon choix est souvent de ne pas viser “parfaite CSP” immédiatement. Visez une CSP robuste qui couvre les domaines externes et bloque les contenus les plus dangereux, puis améliorez par itérations.

image

L’objectif n’est pas la perfection théorique, c’est une sécurité progressive mesurable.

Deux règles simples pour ne pas vous piéger

1) ne partez pas d’une CSP “ultra stricte” sur un site qui n’a pas été observé. Vous aurez des casses immédiates, et vous perdrez du temps.

2) ne gardez pas des directives permissives plus longtemps que nécessaire. Dès que les violations cessent, cherchez à réduire l’excès.

Ces deux règles semblent évidentes, mais elles évitent la plupart des échecs. J’ai vu des sites bloqués par une CSP trop stricte, puis “relâchés” sans suivi, en conservant des permissifs indéfiniment.

Passer en revue votre CSP comme un produit, pas comme un réglage

Une CSP n’est pas un patch qu’on applique une fois. Elle évolue avec:

    les mises à jour de plugins les changements de thème les scripts ajoutés par une campagne marketing les tests A/B la modification de votre architecture (nouveau CDN, nouveau CDN fonts, nouveau service de chat, etc.)

La bonne gouvernance est de prévoir une petite routine: après chaque ajout important, relancez votre test navigation et vérifiez les violations. Une fois le système en place, les changements se gèrent rapidement.

Récapitulatif des étapes recommandées

Pour garder une trajectoire claire, je résume le parcours, sans prétendre que c’est la seule façon de faire:

    déployez une CSP de travail avec des autorisations réalistes démarrez par la collecte de violations testez les pages clés avec un usage réel réduisez les sources au minimum et retirez les permissifs quand c’est possible maintenez la CSP après chaque changement majeur

C’est cette discipline qui transforme la CSP d’une contrainte en levier de sécurité.

Et si vous voulez aller plus loin ?

Si vous devez renforcer encore plus, les prochaines étapes naturelles consistent à:

    passer à des nonces pour les scripts inline quand c’est faisable sur votre stack restreindre plus fortement default-src au lieu de laisser trop large utiliser des règles par sous-domaine, si votre architecture s’y prête affiner connect-src pour éviter que des endpoints tiers soient accessibles

La CSP peut devenir très précise, mais il vaut mieux y arriver progressivement, en restant fidèle au comportement réel de votre WordPress.

Si vous me donnez votre configuration (hébergement, présence d’un CDN, plugins importants, intégrations type analytics ou consentement), je peux vous proposer une CSP de départ adaptée, avec une stratégie de durcissement en plusieurs étapes, et surtout un plan de test concret pour éviter les casses.