Quand un site WordPress se fait compromettre, le premier réflexe est souvent de “réinstaller”. C’est rarement suffisant. Même après nettoyage du code et des fichiers, le risque revient si la configuration web facilite les mêmes erreurs. J’ai déjà vu des cas où la compromission venait d’une simple combinaison, un répertoire mal verrouillé, un fichier de configuration mal interprété, et une règle Apache trop permissive qui a laissé passer un webshell via un chemin inattendu. On a beau patcher WordPress, si Nginx ou Apache continue d’exposer ce qu’il ne devrait pas, l’attaquant n’aura qu’à replonger.
Le but de ce billet est de donner une approche pragmatique pour durcir nginx et Apache autour de WordPress, surtout dans un contexte de “site WordPress infecté”. On ne cherche pas la perfection théorique, on cherche à réduire la surface d’attaque, rendre la configuration plus “déterministe”, et limiter les chemins où un comportement inattendu peut redevenir un problème.
Partir du bon diagnostic, sans supposer
Avant de toucher à la config, je commence par relier l’incident à ce que le serveur est capable de faire. Deux questions reviennent tout le temps.
Première question : l’attaquant a-t-il écrit dans des zones accessibles par le web sans que WordPress soit au centre du mécanisme ? Un exemple classique, des fichiers dans des dossiers de sauvegarde, des chemins uploadés puis servis, ou des interprétations d’extensions inattendues.
Deuxième question : qu’est-ce qui a été modifié depuis l’incident ? Sur un serveur déjà compromis, les changements “simples” peuvent masquer des modifications persistantes. Je vérifie donc les fichiers de configuration et ceux qui les incluent, les virtual hosts, et les fichiers générés automatiquement. Si vous utilisez des panneaux de contrôle, il y a souvent une couche qui réécrit nginx ou les vhosts Apache.
Ce travail de lecture change tout, parce qu’il oriente les durcissements. https://gardewp.fr/nettoyage-malware-wordpress/ Par exemple, si vous découvrez que Apache interprète des fichiers qui ne devraient pas l’être, vos priorités ne seront pas les mêmes que si le problème vient d’un répertoire exposé ou d’un module non nécessaire.
Les principes qui protègent vraiment
Un site WordPress repose sur un modèle clair : le trafic arrive, passe par PHP (via FPM), WordPress traite les requêtes, puis la réponse sort. Tant que le serveur reste dans ce modèle, beaucoup d’attaques perdent en efficacité. Les durcissements que je recommande pour nginx et Apache se résument à quelques principes.
D’abord, interdire l’exécution de scripts en dehors de ce qui sert réellement. Ensuite, empêcher l’accès direct à des fichiers sensibles. Puis, éviter les comportements ambigus, ceux qui laissent le serveur décider à votre place. Enfin, ajouter des garde-fous de cohérence, comme les redirections strictes, une politique de headers minimalistes, et des règles qui bloquent les méthodes non nécessaires.
Cette logique est importante aussi parce qu’elle évite d’appliquer des “recettes” sans comprendre. Dans le monde réel, une règle trop agressive peut casser l’upload, un rewrite mal posé peut bloquer l’admin, et un bloc de sécurité peut empêcher l’export ou l’API. On veut durcir, pas “casser proprement”.
Nginx : durcir les points sensibles autour de WordPress
Nginx est souvent plus simple à raisonner qu’Apache pour ce qui touche aux interprétations, mais il suffit d’une mauvaise règle pour exposer un chemin. Sur WordPress, le pivot, c’est généralement le bloc server et la façon dont on relaie vers PHP.
1) Verrouiller l’accès aux fichiers et dossiers non destinés au web
Dans nginx, il faut être particulièrement strict sur les fichiers .php, .ini, et les répertoires à risque. Je vois fréquemment des configs où seuls les dossiers “classiques” sont protégés, alors que l’attaquant a un talent pour viser des chemins moins visibles.
Concrètement, je vérifie trois familles d’accès :
- les fichiers “config” et “données” que WordPress n’est pas censé servir, les dossiers de cache ou de logs qui contiennent parfois des informations, les répertoires uploadés où un attaquant peut déposer un fichier et tenter une exécution.
Si vous avez des répertoires custom ou une architecture en sous-dossiers, adaptez. Ce qui compte est la cohérence avec votre structure réelle.
2) S’assurer que PHP est servi via FPM uniquement
Le piège le plus fréquent est une configuration où nginx interprète trop d’extensions comme du PHP, ou où des requêtes “tordues” peuvent contourner la logique. Dans un contexte de site WordPress infecté, je considère que l’attaquant a déjà trouvé une façon de parler au serveur. Donc je limite le périmètre PHP à ce qui est nécessaire.
Autrement dit, je préfère une configuration PHP qui colle au chemin attendu, avec un location qui pointe sur un handler unique. Si vous utilisez PHP-FPM via socket, c’est encore plus net, mais les principes restent : une seule porte d’entrée, pas de variantes.
3) Bloquer les expositions directes des chemins WordPress
WordPress expose tout un univers de fichiers, mais tous ne doivent jamais être servis tels quels. Certains sont déjà publics par nature, d’autres non. Sur une installation standard, je bloque en priorité l’accès direct à des fichiers qui contiennent du code ou des configurations, notamment côté racine.

Cela ne veut pas dire “interdire toute la racine”. WordPress a besoin de index.php, de .well-known selon vos besoins, et de routes normalisées via rewrite. On choisit donc des exceptions contrôlées.
Dans une pratique courante, je mets en place une règle qui refuse les requêtes qui tentent d’accéder à des fichiers dotés d’une extension non utile. Ce type de règle doit être testé, parce que certains plugins ou outils peuvent demander des fichiers statiques portant des noms “bizarres”. Le bon réflexe consiste à tester sur staging, ou à prévoir une fenêtre de rollback.
4) Reinforcer les règles de redirection et de méthode HTTP
Les redirections aussi sont un terrain d’attaque indirect. Une redirection mal ciblée peut exposer un chemin en clair, ou provoquer des doubles traitements. Pour la méthode HTTP, je m’en tiens à l’idée suivante : si un site WordPress ne doit pas accepter autre chose que du trafic web classique, les méthodes comme TRACE ou TRACK sont à désactiver.
Même si l’impact direct dépend du moteur et des modules, la réduction de surface vaut le coup. Elle ne remplace pas d’autres protections, mais elle rend l’attaque plus laborieuse.
Petit retour d’expérience
Sur un site où l’accès à certains scripts uploadés avait été tenté, la cause ne venait pas de WordPress lui-même. Nginx avait été configuré pour servir des fichiers de manière trop permissive dans un bloc “générique”, celui qui correspond à un chemin de type “dépôt”. En durcissant uniquement ce bloc, sans toucher à WordPress, on a supprimé le vecteur. La compromission a cessé de se répliquer, même si l’infection d’origine avait déjà été nettoyée. C’est typiquement ce que je veux dire quand je dis que la config est un prolongement de la sécurité applicative.
Apache : durcir les interprétations et éviter les contournements
Apache est puissant, et c’est justement là que le risque apparaît. Un mauvais couple AllowOverride, Options, ou une règle de réécriture mal comprise peut permettre des comportements inattendus. Si vous avez une expérience récente avec une compromission, je recommande de traiter Apache comme un système qui peut être “trop flexible”, et de la rigidifier.

1) Désactiver l’exécution de scripts dans les répertoires non nécessaires
La directive Options et le comportement des répertoires sont les points où je mets le plus de vigilance. Le but est de s’assurer que seuls les chemins prévus peuvent exécuter du code.
Sur WordPress, l’exécution doit passer par index.php via les règles de réécriture, et par PHP-FPM si vous utilisez SetHandler ou un handler PHP. Les répertoires de téléchargement, eux, ne doivent pas exécuter de scripts, même si l’extension ressemble à du PHP.
Je vérifie aussi les permissions côté filesystem. Sur un serveur compromis, l’attaquant peut avoir changé chmod ou chown. Même une config Apache parfaite ne tient pas longtemps si un fichier est déjà au bon endroit avec les bons droits. Le durcissement n’est utile que s’il s’accompagne d’un modèle de droits.
2) Forcer la logique de réécriture sans ambiguïté
Les règles mod_rewrite sont souvent la base de WordPress. Mais elles peuvent être la base d’une dérive si on les modifie “à la main” après un incident, surtout quand on copie colle des fragments trouvés sur internet.
Je recommande de :
- conserver la logique WordPress “standard” et de l’isoler dans un vhost clair, éviter les réécritures qui réinterprètent des extensions de manière dynamique, faire attention aux exceptions pour /wp-admin, /wp-json, et les chemins de plugin.
Le détail qui m’a piqué plus d’une fois, c’est l’interaction entre des règles générales dans le vhost et des directives spécifiques dans des fichiers .htaccess. Si AllowOverride est trop large, n’importe quel fichier déposé dans un répertoire peut modifier le comportement. En cas de compromission, je préfère réduire https://gardewp.fr/ cette flexibilité, au moins temporairement le temps de stabiliser.
3) Bloquer l’accès à des fichiers sensibles
Apache peut servir accidentellement des fichiers s’il n’y a pas de règles explicites. Un attaquant n’a pas besoin de casser WordPress si la config lui donne accès à des fichiers de configuration, des sauvegardes, ou des logs.
Je privilégie des règles qui bloquent le listing implicite, interdisent l’accès direct aux extensions non nécessaires, et protègent les fichiers dotés d’une signification particulière. Par exemple, les fichiers commençant par un point, ou ceux avec des extensions “config”, sont souvent des cibles.
4) Réduire les modules et les directives réellement utilisés
Sur Apache, la sécurité passe aussi par la discipline. Chaque module activé est un morceau de surface. Je ne dis pas qu’il faut désactiver tout, mais sur un serveur qui héberge WordPress, je vérifie ce qui n’est pas utilisé : WebDAV, certains handlers redondants, ou des modules qui autorisent des comportements non nécessaires.
La plupart des serveurs “de prod” sont chargés pour des raisons historiques. Après un incident, c’est un moment opportun pour remettre le serveur à plat. Les économies de temps viennent ensuite, quand vous aurez besoin de reconfigurer un vhost en urgence.
Le nerf de la guerre : .htaccess, Override, et cohérence
Beaucoup d’installations WordPress utilisent des fichiers .htaccess pour la réécriture et quelques protections. En environnement compromis, c’est un point à traiter avec un mélange de méfiance et de méthode.
Si .htaccess est activé en écriture, un attaquant peut y déposer des directives qui modifient la route, redirigent vers un script, ou créent une logique d’exécution. Dans certains cas, le fichier est aussi modifié par des plugins. Donc je ne conseille pas de “couper sans réfléchir” toute la structure, mais je conseille d’établir une cohérence.
Une approche raisonnable consiste à :
- comparer .htaccess avec une référence saine (idéalement issue de la même version, même configuration plugin), vérifier si des directives anormales apparaissent, limiter le scope de ce que .htaccess peut faire avec AllowOverride, contrôler la chronologie des modifications via l’historique ou les timestamps.
C’est précisément la différence entre “je bloque tout” et “je verrouille ce que j’ai vraiment besoin d’autoriser”.
Durcissement immédiat : un plan court et utile
Voici ce que je fais dans les heures qui suivent le nettoyage initial, quand l’objectif est d’éviter que la compromission ne se répaye. L’idée est d’avoir un plan simple, qui ne dépend pas de débats techniques infinis.
- Revalider les droits filesystem, surtout sur wp-content, les répertoires de thèmes et de plugins, et tous les dossiers où des uploads existent. Revenir à une configuration nginx ou Apache connue, au plus proche de la configuration attendue pour WordPress, en corrigeant explicitement les emplacements exposés. Vérifier l’interprétation PHP, une seule porte d’entrée vers PHP-FPM ou le handler prévu, et interdiction de l’exécution ailleurs. Protéger l’accès direct aux fichiers sensibles, en gardant des exceptions contrôlées pour ce qui doit être public. Tester l’impact sur l’upload, l’admin, et les endpoints fréquents comme /wp-json/ et les URLs de plugin majeurs, avec une fenêtre de rollback.
Cette liste est volontairement courte, parce que le risque après incident, c’est de multiplier les changements en même temps. Chaque changement augmente les chances de perdre la trace de ce qui a réellement été réparé.
Cas délicats : multisite, caches, et chemins non standard
WordPress n’est pas une installation unique. Entre multisite, sous-domaines, préfixes, et plugins de cache, les chemins changent. Et c’est là que des durcissements trop génériques cassent tout.
Multisite
En multisite, vous pouvez avoir des répertoires ou des sous-domaines qui demandent une réécriture plus complexe. Si vous bloquiez des chemins “en dur” sans tenir compte de la structure, vous risquez :
- de casser la résolution des blogs, de provoquer des boucles de redirection, ou d’empêcher le chargement de ressources.
Dans ce contexte, je fais moins de blocages “au niveau racine”, et davantage de blocages sur des extensions ou des dossiers précis.
Plugins de cache et CDNs
Les plugins de cache changent parfois les en-têtes et la gestion des fichiers statiques. Un durcissement qui bloque trop tôt peut interférer avec la mise en cache. Si vous utilisez un CDN, une partie des règles peut être contournée, parce que le CDN sert en amont. Cela ne rend pas la config inutile, mais cela change le diagnostic : l’effet d’une règle peut ne pas se voir en première ligne.
Je traite donc la config comme un garde-fou final, pas uniquement comme un mur en amont.
“Uploads” et noms de fichiers
Beaucoup de compromissions passent par le contournement de l’upload. Ce n’est pas seulement une question de droits, c’est une question de politique sur les types de fichiers. Côté serveur, vous pouvez limiter l’exécution, mais WordPress peut encore stocker des fichiers “bizarres”.
Je préfère une combinaison : restrictions côté serveur et contrôles côté application. Si WordPress a été nettoyé, mais que la logique d’upload reste trop permissive, l’attaquant peut retenter.
Headers et durcissement applicatif via le serveur, sans surcharger
Les headers de sécurité ne suffisent pas. Mais une configuration propre réduit les angles morts, surtout contre le comportement du navigateur et certains scénarios de XSS ou de contenu injecté.
Le point essentiel est de rester prudent : des headers mal choisis peuvent casser l’authentification, les redirections, ou les intégrations. Je limite généralement la voilure à ce qui est “faiblement risqué” dans un contexte WordPress, et je teste.
Si vous ajoutez des headers comme Content-Security-Policy, par exemple, vous devez être prêt à adapter selon les scripts et ressources de vos plugins. Sur un site riche en scripts, CSP “bloquante” peut être pénible. C’est faisable, mais pas en mode urgence.
Comment vérifier que la config durcie a réellement empêché le vecteur
Je ne me contente pas de “ça a l’air mieux”. Je vérifie avec méthode. Sur un serveur, la preuve la plus utile vient souvent de la combinaison logs web + logs système + observation de comportements.
Je regarde :
- les erreurs 403 et 404 qui augmentent après durcissement, la présence d’accès à des chemins sensibles, et l’absence d’exécution inattendue.
Si vos logs commencent à montrer une vague de requêtes bloquées vers des fichiers “typiques” d’une compromission, c’est un bon signe. Bien sûr, ça ne prouve pas que tout est parfait. Mais ça prouve que le vecteur n’a plus la même facilité.
Il m’arrive de comparer avant et après sur une fenêtre de temps similaire, par exemple quelques heures. Les tendances ressortent plus vite que les cas isolés. Sur des attaques opportunistes, la différence est parfois visible immédiatement.
Pièges fréquents quand on durcit nginx ou Apache
Plusieurs erreurs reviennent, et elles sont tellement humaines qu’elles finissent par ressembler à un rituel.
Première erreur, modifier nginx et Apache en parallèle pendant une même session de correction, sans journaliser. Ensuite, impossible de savoir quel changement a eu l’effet.
Deuxième erreur, bloquer des extensions ou des chemins “au doigt mouillé”. Par exemple, bloquer certains formats d’image ou certains fichiers générés par un plugin peut ruiner une fonctionnalité. La solution est de tester l’upload et la navigation des sections “administrateur”, pas seulement la page d’accueil.
Troisième erreur, conserver un .htaccess compromis ou non vérifié, même après nettoyage des fichiers WordPress. Si le fichier a été modifié, il peut réintroduire une règle dangereuse.
Quatrième erreur, confondre “le site ne se charge plus” avec “c’est sécurisé”. Un site cassé peut masquer une erreur de config plus large qui, plus tard, sera contournée.
La durabilité vient de la discipline, pas de l’intensité.
Un point crucial : ne confondez pas durcissement et restauration complète
Durcir nginx et Apache est une étape importante, mais ça ne remplace pas une restauration saine. Si des fichiers PHP ont été altérés, ou si des comptes administrateur ont été créés, ou si des cron jobs malveillants existent, la config ne fera que ralentir.
Dans les pratiques sérieuses, on vise un “triangle” :
Nettoyage applicatif (fichiers et base), Restauration de l’intégrité (droits, fichiers, clés), Durcissement du serveur (nginx/apache) pour empêcher la répétition du scénario.Le serveur est la dernière ligne de défense. Il doit être solide, parce qu’une faille applicative, si elle revient, trouvera un mur plus dur.
Quand appeler un diagnostic plus approfondi
Si après durcissement vous observez encore des tentatives fréquentes, ou si les logs révèlent des patterns cohérents avec une persistance (accès répétés à des chemins d’exécution, réponses anormales, ou présence de fichiers nouveaux), il faut pousser plus loin. À ce stade, il peut être utile de faire analyser :
- les journaux sur plusieurs jours, l’état des fichiers (diffs vs une base saine), les tâches planifiées, et les paramètres du serveur (droits, clés, modules, inclusions).
Je reste prudent, parce qu’un site WordPress infecté peut parfois être “remis à flot” visuellement, mais garder une persistance discrète. L’objectif est de rendre la persistance difficile, voire impossible.
Mini “check” de configuration, sans entrer dans un copier-coller
Pour finir, je veux vous donner un cadre mental, plus utile qu’un bloc de configuration unique.
Quand vous lisez votre configuration nginx ou Apache, posez-vous ces questions dans votre tête :
- Est-ce que je peux expliquer, sans supposer, quel chemin peut exécuter du PHP, et comment ? Quels fichiers sensibles sont bloqués, et est-ce que la règle couvre aussi les chemins inhabituels ? Est-ce que .htaccess (ou les includes) peut être modifié de manière non contrôlée ? Est-ce que mes redirections et rewrites sont cohérents avec les URLs WordPress réelles ? Est-ce que j’ai validé l’upload et les pages d’administration après les changements ?
Si vous pouvez répondre clairement à ces questions, vous avez déjà fait beaucoup de travail de fond. Le durcissement n’est pas un “mode sécurité magique”, c’est une manière de rendre la configuration lisible et difficile à détourner.
Si vous voulez, décrivez votre configuration actuelle (nginx ou Apache, structure mono site ou multisite, présence de .htaccess, et comment PHP est servi). Je peux vous proposer une série de durcissements ciblés, adaptés à vos routes, sans casser les fonctionnalités de vos plugins.