Dans WordPress, l’image la plus fréquente du piratage est un accès à l’administration. Pourtant, beaucoup d’incidents commencent ailleurs, dans un endroit plus banal: un dossier d’upload accessible depuis le navigateur, un thème ou un plugin qui stocke des fichiers temporaires, ou une configuration web qui laisse une porte ouverte à l’exécution de code.
Le point de départ est souvent le même. Un attaquant parvient à déposer un fichier dans votre espace public, par exemple via une faille de type upload, un média mal filtré, une extension vulnérable, ou simplement une mauvaise configuration qui accepte des fichiers non attendus. À partir de là, si votre serveur est capable d’exécuter du PHP depuis ces répertoires, le risque devient immédiat. Si, au contraire, le serveur refuse l’exécution PHP dans ces zones, vous limitez drastiquement la portée de l’intrusion. C’est une défense simple, concrète et souvent sous-estimée.
L’objectif de cet article est de vous aider à sécuriser WordPress en empêchant l’exécution de fichiers PHP dans les répertoires exposés au web. On va parler du fameux “upload” de WordPress, du rôle de .htaccess, de la configuration Nginx, des limites propres à chaque environnement, et de la manière de vérifier que la protection tient vraiment.
Comprendre où WordPress “autorise” l’accès au web
WordPress sert des fichiers via plusieurs chemins. Le plus évident est le dossier des médias, généralement placé sous wp-content/uploads/. Par défaut, WordPress écrit aussi des fichiers dans d’autres zones selon les plugins, la configuration et les mises à jour (par exemple des dossiers temporaires, ou des caches). Le point clé n’est pas “ce que WordPress fait”, mais “ce que le serveur web fait”.
Si le serveur est configuré pour interpréter toute extension .php comme du code, alors un fichier déposé avec un nom du type image.php peut finir interprété. Le serveur peut être configuré de façon à exécuter le PHP même depuis un sous-dossier censé contenir uniquement des images, des PDFs ou des documents. Dans ce cas, une simple écriture de fichier peut devenir un exécution à distance.
La logique de protection est donc: même si un fichier malveillant arrive dans un répertoire accessible, il doit être servi comme un fichier inerte, ou rejeté. Prévenir l’exécution de PHP dans ces dossiers, c’est réduire la capacité d’un attaquant à passer de “déposer” à “exécuter”.
La différence entre “empêcher l’upload” et “empêcher l’exécution”
On confond souvent deux niveaux de sécurité:
1) Empêcher l’upload d’un fichier dangereux (contrôles côté application, filtrage par type MIME, restrictions d’extension, antivirus, etc.). 2) Empêcher l’exécution du PHP dans des emplacements où du code ne devrait jamais être exécuté.

Le niveau 1 est idéal, mais il dépend de votre code, des plugins, des mises à jour, et de la qualité de l’implémentation. Le niveau 2 est du ressort de l’infrastructure. Même si une vulnérabilité d’upload survient, ou même si un contrôle applicatif échoue, le niveau 2 peut casser la chaîne.
Dans une démarche de sécuriser site WordPress, j’ai tendance à raisonner comme en sécurité incendie. Vous n’appuyez pas tout sur l’extincteur au moment où l’étincelle se produit. Vous organisez d’abord la séparation des zones à risque. Ici, la “zone à risque” correspond aux dossiers accessibles depuis le web.
Ce que vous cherchez exactement: PHP exécuté sur quels chemins
Dans les configurations classiques, le dossier à traiter en priorité est:
- wp-content/uploads/ (et idéalement tous ses sous-dossiers, car WordPress organise souvent par année et mois) par extension, les autres répertoires “publics” où vous avez des uploads: selon vos plugins, certains dossiers peuvent être sous wp-content/ ou ailleurs certains environnements autorisent l’écriture dans des dossiers temporaires accessibles, même si WordPress n’a pas vocation à y servir du contenu
Le but n’est pas de casser WordPress. Le but est de dire au serveur: “tu peux servir des fichiers, mais tu ne dois pas interpréter du PHP ici”.
Le cas Apache: .htaccess, et les règles qui comptent
Sur Apache, beaucoup de sites WordPress utilisent des fichiers .htaccess. Ce fichier peut contenir des directives qui modifient le comportement pour le dossier courant et ses sous-dossiers. Quand c’est bien configuré, c’est une excellente couche de protection.
La méthode la plus robuste côté Apache
L’approche la plus utile consiste à “désactiver” l’exécution PHP dans les répertoires d’uploads. Typiquement, on ajoute des règles qui forcent Apache à traiter les fichiers PHP comme des fichiers inertes (ou à empêcher le mapping vers l’interpréteur PHP).
Selon votre manière d’exécuter PHP, les directives exactes varient. Deux cas reviennent souvent:
- PHP géré via mod_php PHP géré via php-fpm avec un mécanisme d’interprétation différent, même si Apache reste en face
Si vous utilisez mod_php, les règles basées sur php_flag et php_value peuvent être pertinentes. Si vous utilisez PHP-FPM, on se concentre plutôt sur l’empêchement d’exécution via restriction de handler.
Au lieu de vous donner une recette “une seule et unique ligne pour tout le monde”, voici la logique à viser, parce qu’elle évite les mauvaises surprises:
- forcer “pas de moteur PHP” ou, plus réalitairement, empêcher les fichiers .php d’être traités par le handler PHP dans ces dossiers et vérifier ensuite avec un test concret
Un exemple de configuration ciblée
Dans wp-content/uploads/, vous pouvez placer un fichier .htaccess (ou mettre le bloc approprié si vous en avez déjà un, et fusionner proprement). L’idée est d’ajouter des directives qui empêchent l’exécution des scripts PHP dans ce dossier.
Le point délicat, c’est que chaque hébergeur a son propre “modèle”. Certaines plateformes appliquent déjà des règles globales. Certaines utilisent des templates préconfigurés. Dans ce contexte, ajouter un bloc générique peut, au mieux, ne rien changer, au pire, casser du comportement attendu pour d’autres fichiers.
Mon conseil, quand vous travaillez sur .htaccess, est de procéder en deux temps: préparer une règle minimaliste, puis valider avec un test.
Le cas Nginx: pas de magie, mais une règle claire
Si vous servez WordPress avec Nginx, vous n’avez souvent pas de .htaccess fiable, car Nginx ne lit pas ces fichiers comme Apache. La protection se fait au niveau de la configuration serveur.
La logique est la même: dans les “locations” qui correspondent à vos uploads, vous devez éviter l’interprétation PHP. Typiquement, vous définissez une règle pour les fichiers statiques, et vous vous assurez qu’ils ne passent pas dans la clause qui envoie vers fastcgi_param et PHP-FPM.
Le piège classique côté Nginx est l’inversion involontaire des règles: une location trop permissive peut “capturer” les requêtes et les envoyer vers PHP, même depuis un dossier que vous pensiez protégé.
L’approche saine consiste à vérifier l’ordre des directives, et à tester le rendu d’un fichier .php dans uploads (ou un faux fichier de test, non exécutable) avant de déployer.
Validation: comment savoir si le PHP est réellement empêché
La sécurité “théorique” est un piège. Vous devez valider. Et la validation doit être prudente, sans créer de risque inutile.
Un test concret, sans se mettre en faute
L’idée est de vérifier que:
- un fichier .php placé dans wp-content/uploads/ n’est pas exécuté et que sa réponse est celle d’un fichier statique, ou une erreur d’accès, selon vos règles
Concrètement, le test le plus simple consiste à créer un fichier de test qui contient une signature reconnaissable, le déposer dans uploads, puis l’appeler via l’URL publique. Si le serveur exécute le PHP, vous verrez la signature interprétée. S’il refuse, vous verrez soit du texte brut, soit un code d’erreur, soit une réponse différente.
Évidemment, ne gardez pas ce fichier de test. Faites-le, vérifiez, puis supprimez.
Les signatures que j’utilise en pratique
Je privilégie des signatures courtes qui évitent de faire déclencher d’autres comportements. Par exemple, un texte unique renvoyé par le code PHP. Si vous voyez le texte, c’est mauvais. Si vous voyez une erreur, ou si le texte PHP apparaît comme du texte, la règle fonctionne.
Si vous êtes en environnement mutualisé, évitez de multiplier les tests, car certains hébergeurs journalisent tout. Un seul test bien ciblé suffit.
Préparer la protection sur plusieurs niveaux (et accepter les compromis)
Quand on sécurise WordPress, on a tendance à vouloir “tout interdire”. Sauf que WordPress et certains plugins manipulent des fichiers variés. Une interdiction trop large peut provoquer des effets secondaires.
Les compromis à anticiper
- Si vous bloquez trop agressivement les règles .php dans certains dossiers, vous pourriez casser des fonctionnalités qui utilisent PHP dans des répertoires internes accessibles. Dans la pratique, c’est rare pour uploads, mais possible pour d’autres dossiers. Si vous renommez des chemins ou changez des mappings, certaines archives ou flux peuvent être impactés. Si vous mettez une règle à un mauvais endroit, elle peut ne pas s’appliquer, sans générer d’erreur visible.
C’est pour cela que je recommande de cibler uniquement les répertoires où la présence de PHP n’est pas attendue, et de valider.
Le cas particulier de ce qui “ressemble” à du PHP mais n’en est pas
Une autre source de confusion: certaines attaques utilisent des noms trompeurs, par exemple:
- double extension: image.php.jpg caractères de fin, espaces, ou variantes fichiers SVG ou HTML stockés comme “médias”, selon la manière dont le navigateur les interprète
Votre protection “pas d’exécution PHP” ne suffit pas à elle seule contre tout. Par contre, elle limite fortement la partie exécution. Si l’attaquant dépose un fichier qui n’est pas exécuté comme PHP, il ne peut pas prendre le contrôle du serveur via du code.
En parallèle, vous voulez aussi réduire l’exposition des fichiers qui peuvent mener à du contenu actif côté navigateur. Là, on touche à la sécurité XSS et à la manière dont WordPress sert les médias, parfois avec des en-têtes de type Content-Security-Policy ou X-Content-Type-Options. Ce sujet est plus large, mais il est lié à votre démarche.
Mettre un garde-fou sans casser les médias: stratégie concrète
Voici une façon de raisonner et d’agir, sans tomber dans l’excès.
Une checklist de durcissement ciblé
- Ciblez d’abord wp-content/uploads/ et sous-dossiers, car c’est le point d’entrée le plus fréquent pour des dépôts de fichiers. Vérifiez si votre PHP est géré via Apache mod_php ou via Nginx, ou via un mécanisme spécifique chez votre hébergeur. Ajoutez la règle de blocage au bon endroit (.htaccess pour Apache, bloc location pour Nginx). Créez un fichier de test .php uniquement pour vérifier, puis supprimez-le immédiatement après. Contrôlez les logs applicatifs et serveur sur une courte période pour détecter des tentatives répétées ou des erreurs inattendues.
Cette séquence évite la situation classique: “j’ai modifié .htaccess, mais je n’ai jamais vérifié”. Sans validation, on s’illusionne.
Edge cases: quand l’interprétation PHP dépend de la configuration du serveur
Il existe des environnements où la notion “empêcher l’exécution PHP dans un dossier” n’est pas triviale. Quelques exemples que j’ai rencontrés lors d’audits, sans prétendre à l’exhaustivité:
- Certains stacks utilisent des règles globales d’exécution qui ignorent des .htaccess si l’hébergeur a désactivé les overrides. D’autres stacks se basent sur le path plutôt que l’extension, avec des règles qui peuvent “capturer” des requêtes inattendues. Certains mécanismes de cache ou de transformation peuvent servir le contenu différemment selon headers, et donner une impression de protection alors que le traitement existe ailleurs.
Le bon réflexe reste le même: tester et observer. Si vous avez accès à un environnement de staging, reproduisez-y l’analyse avant de toucher à la production.
Ne pas oublier le reste: fichiers de configuration et surface d’écriture
Empêcher l’exécution PHP dans uploads réduit une partie du risque. Mais si un attaquant peut créer des fichiers dans des zones où PHP est exécuté, vous devez penser plus large.

Par exemple, selon les cas:
- la capacité d’écrire dans wp-content/ peut être exploitée via certains schémas de plugin des scripts temporaires peuvent apparaître et être accessibles des fichiers de sauvegarde, journaux ou archives peuvent contenir des informations sensibles, ou être servis au public
Ce n’est pas seulement une question de “PHP”. C’est une question de contrôle des emplacements d’écriture et des droits. Une défense efficace combine “limiter où on écrit” et “limiter ce qui s’exécute”.
Droits de fichiers et permissions: utile, mais pas suffisant
On pense souvent aux permissions Unix, et c’est pertinent. Si le serveur n’a pas les droits d’écrire dans certains dossiers, l’injection de fichiers devient plus difficile. En revanche, si WordPress ou un plugin peut écrire dans uploads, alors les permissions ne suffisent pas à empêcher un attaquant de déposer du contenu dans ce dossier.
Autrement dit: les permissions participent à la sécurité, mais votre objectif ici reste de neutraliser l’exécution PHP. Même avec de bonnes permissions, vous voulez que uploads reste non-exécutable.
Plugins et “hardening”: ce qu’ils peuvent faire, ce qu’ils ne remplacent pas
Des plugins de sécurité existent, et certains proposent des contrôles de type “désactiver l’exécution dans uploads”. Ils peuvent aider, surtout si votre hébergeur ne vous donne pas la main sur la configuration serveur.
Mais je garde une règle simple en tête: un plugin ne remplace pas une règle web server. Un plugin peut écrire des directives, modifier un .htaccess, ou appliquer une logique applicative. Si la configuration serveur ne suit pas, le risque peut rester.
En pratique, j’aime voir les plugins comme un outil de consolidation: ils centralisent des vérifications, alertent sur des changements, et apportent des protections autour de WordPress. La couche “pas d’exécution PHP dans uploads” doit, elle, être validée au niveau serveur.
Cas réaliste: quand une image devient un point d’entrée
Je me souviens d’un incident où un site avait subi des tentatives répétées. Rien dans l’interface n’indiquait une compromission immédiate. L’équipe pensait avoir “empêché l’upload”.
En creusant les logs, on a vu des dépôts de fichiers avec des extensions trompeuses dans uploads. Grâce à la correction des règles côté serveur, le PHP n’a pas été exécuté. Le contenu était accessible, mais inerte. La campagne a perdu une partie de son efficacité, et le temps de réaction a compté: en surveillant l’activité, on a pu nettoyer les fichiers déposés et corriger la cause côté application.
Ce scénario illustre bien la philosophie. Même si vous n’empêchez pas tout dépôt, vous pouvez empêcher l’exécution, donc limiter l’impact.
Exemple de plan d’action selon votre stack
Au lieu de vous donner un bloc “copier-coller” unique, voici comment décider rapidement.
Si vous êtes sur Apache, la piste la plus directe est .htaccess dans wp-content/uploads/, ou une règle globale qui cible explicitement ce chemin. Ensuite, on teste avec un fichier de test.
Si vous êtes sur Nginx, on inspecte votre configuration de site. On cherche la partie qui route les requêtes vers PHP-FPM. Puis on s’assure que la location correspondant aux uploads n’entre pas dans ce routage.
Enfin, si vous êtes sur un hébergement managé qui verrouille la configuration, vous cherchez l’équivalent côté interface, ou un mécanisme fourni par l’hébergeur. Dans ces cas, la validation reste non négociable: test d’exécution, puis suppression.
Garder la protection dans la durée
Une règle qui marche un jour peut cesser de marcher si:
- vous migrez l’hébergement vous remplacez un thème ou un plugin “qui gère .htaccess” vous activez une option de sécurité qui écrase certaines directives vous mettez en place une couche de cache ou un reverse proxy qui modifie le routage
Je recommande de considérer cette protection comme un élément de votre “maintenance”. Une fois par période, vous vérifiez les deux points:
- la règle est bien en place (présence et cohérence du fichier, ou configuration Nginx) le comportement reste conforme (un test rapide, ou une vérification plus indirecte via logs si vous ne voulez pas déposer à nouveau)
Il n’y a rien de pire que de “dormir” sur une sécurité qui n’est plus active.
Ce que vous gagnez en empêchant l’exécution
Quand la défense est correctement mise en place, vous obtenez plusieurs bénéfices:

- l’attaquant doit trouver un autre chemin pour exécuter du code la charge utile d’un dépôt de fichier est réduite, même si le dépôt reste possible vous gagnez du temps de détection et d’investigation, car le comportement observable change
Et surtout, c’est une mesure concrète. Vous pouvez la mettre en place, la tester, et la conserver.
Rester pragmatique: une règle, mais pas un miracle
Prévenir l’exécution PHP dans wp-content/uploads/ est un durcissement qui “coupe” une branche entière de scénarios d’attaque. C’est puissant, mais ce n’est pas une immunité. WordPress dépend d’un écosystème de thèmes et plugins. Les vecteurs changent. Les erreurs humaines existent.
La bonne attitude, c’est de combiner:
- contrôles d’upload côté application durcissement serveur pour éviter l’exécution surveillance, mises à jour et hygiène de droits et validation régulière
C’est exactement la posture qui rend la sécuriser site WordPress efficace, pas seulement pendant une journée de correction, mais sur la durée.
Dernier mot de méthode: partez de votre réalité, pas d’une recette
Si vous devez retenir une seule idée, c’est celle-ci: la protection doit être adaptée à votre serveur, à votre façon d’exécuter PHP, et à votre structure de fichiers. Une règle mal placée peut ne rien faire. Une règle https://gardewp.fr/securite-wordpress/ trop large peut casser un fonctionnement inattendu.
Prenez le temps de choisir le bon point d’application, puis testez réellement. Une fois que vous avez vu le comportement changer sous vos yeux, vous passez du “on pense que c’est protégé” à “c’est protégé”. Et ça, c’est le genre de confiance qu’on peut exploiter sereinement.
Si vous me dites quel serveur vous utilisez (Apache ou Nginx), et comment PHP est servi (php-fpm ou mod_php si vous savez), je peux vous proposer une configuration plus précise et adaptée à votre cas, avec un plan de test et de rollback.