Quand on parle de sécurisation WordPress, on pense souvent aux plugins, aux thèmes, aux mises à jour, à la sécurité côté web. Tout juste. Il y a un autre levier plus discret, mais redoutablement efficace, surtout dans les environnements où l’on a déjà “fait le maximum” sur WordPress: limiter les privilèges avec lesquels le code PHP s’exécute.
Dans la plupart des intrusions réelles, une étape clé ressemble à ceci: un attaquant exploite une faiblesse applicative (un plugin, un endpoint, une élévation de privilège). Ensuite, il essaie d’aller plus loin dans le système. Ce que PHP peut lire, écrire, exécuter, devient alors le plafond des dégâts. Si PHP tourne avec trop de droits, le plafond s’effondre. Si PHP est enfermé au contraire, l’incident devient plus coûteux pour l’attaquant et plus simple à contenir.
Comprendre le problème: “PHP a accès à quoi ?”
WordPress exécute du PHP pour servir le contenu, traiter les formulaires, gérer l’authentification, lancer les requêtes vers la base de données, etc. Le système d’exploitation et la configuration serveur déterminent les droits effectifs du processus PHP.
Deux notions reviennent dans la pratique.
La première, ce sont les droits Unix (utilisateur, groupe, mode d’accès) sur le répertoire WordPress, les fichiers, et les répertoires temporaires. Si le processus PHP est propriétaire de ces fichiers, ou s’il peut tout écrire, alors n’importe quel code injecté peut souvent effacer, remplacer, ou déposer des charge utiles.
La seconde, ce sont les contraintes applicables au niveau PHP et du serveur: restriction d’accès à certains chemins (open basedir), désactivation de fonctions dangereuses (disablefunctions), politique de confinement via SELinux ou AppArmor, ou séparation stricte des comptes pour l’exécution.
Sur un hébergement mutualisé, ce sujet peut sembler théorique. Pourtant, j’ai vu des cas très concrets où “ça ne craque pas sur le web”, mais où une fois la prise obtenue, l’attaquant pouvait écrire dans des emplacements sensibles, modifier des fichiers de configuration, ou lire des éléments qui ne devraient jamais quitter le périmètre de WordPress.
Le bon modèle d’exécution: “PHP aussi doit être un invité”
La meilleure posture est simple à dire, plus difficile à obtenir selon l’hébergeur: PHP doit tourner avec un compte dédié, avec les privilèges strictement nécessaires.
Dans les environnements modernes, PHP-FPM est souvent le point d’application. L’idée est d’avoir un pool PHP par site ou par application, avec un utilisateur système spécifique, et un répertoire WordPress qui appartient à un compte d’écriture contrôlé (souvent l’utilisateur de déploiement), tandis que le compte PHP n’a que les droits d’exécution et, au besoin, d’écriture sur quelques dossiers précis.
Sur des serveurs correctement gérés, on voit aussi un découpage: l’accès web ne doit pas donner accès direct à un compte “administrateur” du système, ni permettre une écriture illimitée sur tout l’arborescence.
Quand ce modèle est absent, on se retrouve avec des configurations où le processus PHP tourne avec des droits trop larges pour des raisons de confort: permissions mises à “large”, fichiers appartenant à l’utilisateur du webserver, ou même exécution avec un compte plus privilégié que nécessaire.
Cas typiques qui posent problème
Sans faire de procès d’intention, certaines situations reviennent.
D’abord, le répertoire WordPress en mode “tout le monde peut écrire” (par exemple, permissions très ouvertes sur des dossiers comme wp-content, ou une logique qui évite les erreurs d’upload en “ouvrant” plus que nécessaire). Ça rend les incidents plus graves dès que PHP est compromis.
Ensuite, l’héritage de droits: si un dossier est trop permissif, ses sous-dossiers le deviennent souvent. Le correctif devient alors une opération de remise à plat, avec risque de casser des uploads ou des caches.
Enfin, l’absence de confinement au niveau serveur: sans open_basedir, sans restrictions de fonctions, sans profil SELinux, tout code PHP a beaucoup de marge.
Vérifier les droits avant de “durcir”: l’erreur fréquente
Le durcissement ne se fait pas sur un coup de tête. J’ai appris à mes dépens qu’un changement de permissions mal calibré se traduit rapidement par des symptômes pénibles: erreurs 500, échecs d’upload, impossibilité d’installer des plugins, plantages lors de la génération d’images, ou impossibilité d’écrire le cache.
Le bon réflexe est de mesurer ce que WordPress et votre stack ont réellement besoin d’écrire.
WordPress a des exigences variables selon les réglages. Le noyau écrit notamment dans wp-content (uploads, caches selon la configuration), et certaines extensions utilisent également des dossiers temporaires. Mais il n’est pas nécessaire que PHP puisse tout écrire partout.
Avant de modifier quoi que ce soit, faites l’inventaire des écritures observées (logs, comportement en préproduction) et vérifiez les droits existants. Sur une machine de test, vous pouvez reproduire un upload, l’activation de plugin, la génération de miniatures, et les opérations qui déclenchent des écritures.
Segmenter l’arborescence: “écrire peu, exécuter bien”
Limiter les privilèges PHP, c’est aussi limiter l’aire d’écriture. L’approche la plus robuste consiste à séparer:
- l’arborescence du code (fichiers PHP) qui doit être modifiée uniquement lors des déploiements contrôlés les répertoires d’exécution dynamique et de stockage où l’application doit écrire, de manière contrôlée
Concrètement, le code WordPress et les plugins peuvent être “en lecture seule” pour le compte PHP. Les téléchargements, caches, et fichiers générés peuvent être “écriture autorisée” uniquement pour ce qui est nécessaire.
Le piège, c’est d’oublier la réalité opérationnelle: certains plugins demandent plus de droits que prévu, notamment ceux qui modifient des modèles, génèrent des fichiers, ou écrivent des structures dans wp-content. Si vous bloquez trop tôt, vous ne sécurisez pas, vous cassez.
D’où l’intérêt de la logique de confirmation: durcissez graduellement et vérifiez le fonctionnement.
Un point central: ownership et modes sur le système
Le duo le plus utile est souvent: propriétaire du code et propriétaire d’écriture, en distinguant le compte de déploiement et le compte PHP.
Si vous gérez vous-même vos serveurs (ou si votre hébergeur vous laisse adapter), le schéma qui marche bien ressemble à:
- répertoires et fichiers WordPress et plugins détenus par un utilisateur “de déploiement” exécution PHP via un compte dédié, sans droit d’écriture sur le code dossiers d’uploads, de cache, et de fichiers temporaires autorisés à l’écriture pour le compte PHP
Le réglage fin des permissions (modes et groupes) dépend de votre système et de votre pratique de déploiement. Mais une règle d’or reste stable: si le code PHP est écrivable par le même compte que celui qui l’exécute, un attaquant qui obtient l’exécution peut transformer votre serveur en coffre à outils.
Traduction concrète en contrôles
Vous pouvez faire deux choses pratiques, sans vous perdre dans les détails.
D’abord, confirmer quel utilisateur exécute réellement PHP-FPM ou le processus d’exécution de PHP. Ensuite, vérifier les droits sur les dossiers où WordPress écrit effectivement.
Voici un mini-checklist que j’utilise avant et après durcissement.
- Identifier l’utilisateur et le pool PHP qui servent WordPress (PHP-FPM, mod_php, autre) Contrôler les propriétaires et groupes des dossiers wp-content, wp-includes et des thèmes/plugins Vérifier quels dossiers doivent être en écriture pour WordPress (uploads, caches, éventuellement uploads temporaires) Confirmer que le compte PHP ne peut pas écrire dans le code applicatif (wp-includes, fichiers noyau, fichiers plugins thématiques) Tester upload, génération de miniatures et activation de plugin en préproduction
Contrôler PHP côté configuration: open basedir et disablefunctions
Même avec des permissions système propres, il faut se rappeler qu’une compromission applicative donne du code PHP à exécuter. Limiter les privilèges “système” ne réduit pas automatiquement tout l’impact. D’où l’intérêt des restrictions internes à PHP.
open_basedir: empêcher l’accès aux chemins non nécessaires
Open_basedir limite les chemins accessibles par certaines fonctions PHP qui lisent des fichiers. Ce n’est pas une panacée, mais c’est une digue utile. Elle empêche du code injecté d’explorer arbitrairement le système de fichiers.
Dans WordPress, vous pouvez généralement autoriser:
- le chemin du document WordPress le dossier uploads un dossier temporaire cohérent avec votre configuration
Chaque serveur est différent, car des dépendances peuvent exister: librairies, montages, emplacements de logs, répertoires temporaires système. Le durcissement doit être testé, surtout si vous utilisez un stockage déporté ou des traitements d’images qui s’appuient sur des chemins précis.
disable_functions et fonctions “à risque”
Disable_functions n’est pas une sécurité “totale”. Un attaquant peut parfois contourner des limitations si d’autres chemins existent. Mais réduire la surface augmente le coût d’exploitation.

Typiquement, les fonctions liées à la création de processus, à l’exécution de commandes, à l’accès réseau non contrôlé, ou à des fonctions très verbeuses peuvent être désactivées si votre stack ne les requiert pas.
Là encore, j’insiste sur le test: certains plugins ou bibliothèques PHP peuvent utiliser des fonctions que vous pensiez pouvoir couper. L’erreur fréquente est de passer disable_functions trop agressif, puis de perdre des fonctionnalités de traitement image, de diagnostics, ou d’intégration.
Confinement serveur: SELinux, AppArmor, et la différence entre “permissions” et “politique”
Sur un serveur Linux durci, SELinux ou AppArmor apportent une barrière supplémentaire. Là où les permissions Unix disent “qui peut lire/écrire”, les politiques disent “ce type de processus a le droit de faire quoi, dans quels contextes”.
Un cas typique: même si PHP a une permission à lire un fichier, une politique plus stricte peut refuser l’accès. Ou inversement, une politique peut autoriser explicitement le nécessaire, même si des chemins sont plus nombreux que prévu.
C’est rarement un réglage que l’on fait sans accompagnement. Mais quand il est déjà en place, et que vous savez comment votre service PHP est étiqueté, il devient un levier puissant pour limiter ce qu’une compromission PHP peut faire.
Séparer l’administration et le runtime: accès à wp-admin versus droits serveur
Il y a un piège cognitif: confondre contrôle d’accès applicatif et privilèges système.
Limiter les privilèges PHP ne signifie pas “réduire les droits des administrateurs WordPress”. Les rôles WordPress (admin, éditeur, auteur) restent importants, mais ils ne pilotent pas ce que PHP peut faire sur le système.
L’objectif est de faire en sorte que même si un attaquant parvient à obtenir un rôle WordPress élevé (ou à exploiter un plugin), le runtime PHP ne soit pas en mesure d’exécuter des actions système au-delà du strict nécessaire.
C’est là que la séparation compte: compte PHP non privilégié, code en lecture seule, écriture limitée aux dossiers prévus.
Cas pratiques: erreurs courantes et ajustements
J’ai souvent rencontré trois classes d’erreurs lorsqu’on tente de durcir.
1) “Tout est en lecture seule”, mais les uploads cassent
Le symptôme: échec d’upload, ou erreur sur la création de miniatures. Cause habituelle: le dossier uploads ou le sous-dossier temporaire n’a pas la bonne permission, ou le mode n’autorise pas l’écriture au bon utilisateur.
Correction: rendre en écriture uniquement les sous-dossiers nécessaires, et ajuster ownership. Sur certains systèmes, le groupe joue un rôle, et une stratégie de groupes cohérente évite de donner des droits trop larges.
2) Certains plugins “installent” en écrivant dans le code
Certains plugins génèrent des fichiers, modifient des templates, ou écrivent des caches dans des zones proches du code. En théorie, ils devraient respecter un périmètre propre, mais en pratique, ils ne sont pas toujours parfaits.
Si vous verrouillez trop, ils échouent. La bonne approche est de tester plugin par plugin, ou par “famille” de fonctionnalités. Si un plugin nécessite réellement l’écriture ailleurs que dans wp-content/uploads et caches, alors la décision devient une question de compromis: accepter temporairement un droit plus large, ou remplacer le plugin.
3) open_basedir trop strict
Le symptôme: erreurs lors de certaines opérations, pages qui cassent sur certains environnements. Cause: open_basedir n’autorise pas un chemin utilisé en arrière-plan (par exemple pour des traitements d’images, des bibliothèques, ou des fichiers temporaires).
Correction: ajuster open_basedir avec précision, plutôt que de l’étendre au hasard. L’idée reste la même, restreindre l’accès. Si vous ouvrez à “tout”, vous perdez le bénéfice.
Choisir la stratégie selon votre hébergement
Tous les serveurs ne vous donnent pas le même contrôle.
Sur un hébergement mutualisé, vous aurez parfois surtout accès à des paramètres PHP via l’interface (php.ini partiel, .user.ini, ou équivalent), et beaucoup moins sur la configuration du process PHP-FPM et les utilisateurs système. Dans ce cas, open basedir, disablefunctions, et des règles de permissions gérées par l’interface peuvent déjà faire une différence.
Sur un VPS ou un serveur dédié, vous pouvez aller plus loin: ajuster les pools PHP, ownership fin, isolation par site, confinement via SELinux/AppArmor, et verrouillage du code.
Sur des environnements conteneurisés, la logique se rapproche de la philosophie: un utilisateur non root, un système de fichiers monté avec des https://gardewp.fr/securite-wordpress/ options adaptées, et une politique d’exécution qui réduit l’impact d’une compromission.
Le point important: même si vous ne pouvez pas tout faire, commencez par ce qui est réaliste chez vous, sans casser la production.
Une approche graduelle, sans se tirer une balle dans le pied
Un durcissement efficace suit souvent un chemin pragmatique.
D’abord, stabiliser l’existant: sauvegardes, accès en cas de panne, fenêtre de test, et surveillance des erreurs PHP et du webserver.
Ensuite, verrouiller les zones qui n’ont pas besoin d’écrire: code du noyau et des extensions, en laissant l’écriture là où WordPress et ses plugins l’exigent réellement.
Puis, ajouter des restrictions PHP internes: open basedir, et disablefunctions seulement si vous savez ce que votre stack utilise.
Enfin, renforcer côté serveur si les outils existent: politiques SELinux/AppArmor, confinement réseau, et séparation plus nette des environnements.
Une bonne règle: à chaque étape, testez l’ensemble des fonctionnalités sensibles, notamment celles qui touchent aux uploads, aux thèmes et à la génération d’images.
Surveiller après changement: les “signaux faibles”
Quand on modifie les privilèges, les erreurs peuvent être silencieuses au début.
Quelques indicateurs à suivre en pratique:
- erreurs PHP dans les logs (warnings et fatals), même si la page rend “presque” échecs d’upload ou messages d’erreur du back-office décalage dans les traitements d’images (miniatures qui ne se génèrent plus) comportements anormaux des caches (si un plugin ne peut plus écrire, il peut tomber dans un mode dégradé)
Je conseille de regarder aussi le comportement des extensions qui dépendent de chemins système. Un plugin de sécurité, un outil de cache ou un framework de formulaires peut utiliser des chemins temp ou des opérations fichier qui deviennent invalides si vous avez trop serré.
Voici un second mini-checklist, orienté “validation” après durcissement.
- Réussite d’un upload avec un fichier test, puis vérification dans la médiathèque Création de miniatures (si vous utilisez un générateur automatique) Activation ou mise à jour d’un plugin non critique en staging Rechargement des pages qui déclenchent des traitements image ou génération de cache Vérification des logs sur 1 à 2 cycles de trafic (matin, soir, si possible)
Les compromis à assumer: sécurité versus maintenance
Limiter les privilèges PHP améliore la sécurité, c’est indéniable. Mais on ne le fait pas pour obtenir un score théorique.
Le compromis le plus fréquent, c’est la maintenance. Un verrouillage plus strict exige:
- des déploiements contrôlés (pour mettre à jour le code sans que PHP doive avoir des droits d’écriture) des tests lors de l’ajout d’un nouveau plugin une coordination plus fine entre votre processus d’administration WordPress et votre niveau système
Un autre compromis concerne la compatibilité. WordPress et l’écosystème plugin vivent aussi de pratiques “historiques”. Certains plugins ont des dépendances qui demandent des droits plus larges. Le rôle du mainteneur, c’est d’arbitrer: soit on ajuste le périmètre pour ces plugins, soit on remplace les extensions qui ne respectent pas un modèle de droits cohérent.
Enfin, il y a la question de la réponse à incident. Plus vos privilèges sont limités, plus l’incident devient “confiné”. Mais ça doit aussi être traduit en procédure: savoir quels dossiers sont probablement touchés, quels fichiers sont intouchables, et quelles vérifications font sens.


Mettre tout cela au service d’une stratégie globale
Limiter les privilèges PHP ne remplace pas les autres mesures. Ça s’empile.
Des mots de passe solides, des mises à jour rapides, une hygiène de plugins, une protection contre les attaques par force brute, une validation stricte des entrées, tout cela reste essentiel. Mais quand l’application est compromise, la différence se joue aussi sur la capacité à sortir du périmètre.
Un WordPress correctement durci, avec PHP enfermé et droits d’écriture réduits, transforme une compromission potentielle en problème plus maîtrisable. On réduit la surface, on retarde la prise de contrôle, on augmente le coût pour l’attaquant, et on facilite l’investigation.
Si vous ne deviez retenir qu’une idée: la sécurisation WordPress passe aussi par l’OS, et PHP est le pont entre les deux mondes. C’est ce pont qu’il faut rendre étroit.
Si vous voulez aller plus loin (sans tout casser)
Selon votre niveau de contrôle, vous pouvez progresser en deux directions complémentaires:
- renforcer côté système (ownership, droits, confinement, séparation des comptes) renforcer côté PHP (open basedir, disablefunctions, paramètres de sécurité applicables)
Commencez par ce qui est observable et testable chez vous, car la meilleure règle de sécurisation est celle qui tient en production. Le reste, c’est du théâtre. Et avec WordPress, le théâtre finit presque toujours par attirer l’oubli, puis une régression. Le bon durcissement est sobre, mesuré, et maintenable.