Renforcer la sécurité WordPress : gérer correctement les permissions PHP

Quand on parle de “sécurité WordPress”, on pense souvent aux plugins, aux thèmes, aux mises à jour et aux mots de passe. C’est logique, mais dans la pratique, la surface d’attaque la plus silencieuse reste parfois la configuration serveur. Les permissions PHP et, plus largement, les droits d’accès aux fichiers et aux dossiers, décident de ce que WordPress peut lire, écrire, exécuter et, surtout, de ce qu’un attaquant pourrait réussir à faire s’il obtient un accès limité.

J’ai vu des sites compromis sans qu’aucun module “magique” ne soit installé, simplement parce qu’un dossier uploads ou un fichier sensible avait des droits trop ouverts. À l’inverse, j’ai aussi vu des sites tomber en erreur 500 parce qu’on avait “durci” les permissions au point de casser l’exécution PHP ou l’écriture des médias. Le bon réglage n’est pas un chiffre universel. C’est un équilibre entre principe du moindre privilège, contraintes d’hébergement et comportement réel de WordPress.

Ce que les permissions font réellement (et pourquoi ça se voit à l’échelle serveur)

Les permissions sous Linux découlent d’un mélange de droits Unix (lecture, écriture, exécution), de propriétaire (user) et de groupe (group). WordPress n’a pas de conscience des permissions, il tente juste d’ouvrir des chemins. Si l’utilisateur système qui exécute le serveur web (souvent www-data, apache, ou équivalent) n’a pas le bon accès, WordPress échoue. Si, au contraire, les droits permettent à trop de monde d’écrire ou d’exécuter, vous ouvrez une porte.

La nuance est importante. Un fichier peut être lisible par tous, ce n’est pas forcément grave. Par contre, un dossier inscriptible par “tous” devient une zone à risque. Un script PHP exécutable à tort, ou un chemin où des fichiers PHP injectés pourraient être placés, change complètement le niveau d’exposition.

Les permissions “PHP” se posent souvent sous deux angles :

Les droits des fichiers PHP eux-mêmes (exécution autorisée, propriétaire cohérent, pas d’écriture publique). Les droits des dossiers dans lesquels WordPress doit créer ou modifier des fichiers, notamment wp-content/uploads, et parfois des caches, transients et extensions selon la configuration.

En sécurisant les permissions, vous réduisez surtout deux risques classiques :

    l’écriture non autorisée dans des emplacements sensibles (uploads trop ouverts, cache accessible, dossiers en écriture globale), l’exécution non prévue de contenu (fichiers scripts déposés dans un répertoire interprété par PHP).

La logique “principe du moindre privilège”, appliquée à WordPress

L’objectif raisonnable est de donner à l’utilisateur du serveur web uniquement ce dont WordPress a besoin. Le reste doit rester lisible, ou mieux, inaccessible en écriture.

Sur la plupart des hébergements, WordPress s’appuie sur un seul compte de service pour exécuter PHP et lire le code. Ce compte doit pouvoir :

    lire les fichiers du core WordPress, écrire certains dossiers de wp-content (au minimum les uploads), éventuellement écrire des fichiers de cache selon les plugins et la stack (cache disque, optimisation images, scripts de build, etc.).

Ce qui ne doit pas arriver :

    que tout le monde puisse écrire dans le code (le core, les thèmes et les plugins), que les dossiers où WordPress dépose des fichiers soient interprétés de manière inattendue par PHP, que des répertoires “temps réels” ou temporaires soient trop permissifs.

Le piège, c’est que “ça marche chez moi” ne suffit pas. Sur un VPS, la configuration peut être stricte, tandis qu’un mutualisé impose d’autres contraintes. Sur un hébergement géré, on peut aussi remplacer le modèle Unix par des réglages plus complexes via des couches de sécurité.

Comprendre les formats de permissions : les chiffres ne suffisent pas

On voit souvent des conseils du type “mettez 755 aux dossiers et 644 aux fichiers”. C’est un point de départ, mais pas une vérité absolue. Le comportement dépend aussi de :

    l’utilisateur et le groupe effectifs utilisés par le serveur web, le type de système de fichiers, la présence de mécanismes comme SELinux ou AppArmor, la configuration du serveur (Nginx, Apache, interprétation PHP par répertoire), les besoins d’écriture réels (uploads, cache, mises à jour automatiques).

Par exemple, si WordPress doit écrire dans un dossier précis, le serveur web doit avoir le bit d’écriture. Si vous verrouillez trop, vous aurez des échecs de téléchargement d’images, des mises à jour qui échouent, ou des erreurs qui ressemblent à des problèmes de plugin alors qu’il s’agit de droits.

À l’inverse, si vous rendez un dossier “trop écrivable” (par exemple écriture globale), un attaquant ayant seulement la capacité de créer un fichier dans cette zone pourrait tenter de déposer un fichier de script ou d’altérer un fichier interprété.

Dans une logique de renforcement sécurité WordPress, les permissions sont rarement “le réglage final”. Elles s’inscrivent dans une stratégie : séparation des espaces, limitation de l’écriture, et conformité à la manière dont votre serveur interprète PHP.

Dossiers critiques : ceux qui méritent le plus d’attention

Quand je fais une revue sécurité, je commence par les zones où WordPress écrit. Le code du core n’a en général pas besoin d’être modifiable par le serveur web en permanence. Par contre, la création de fichiers médias, les logs éventuels, ou les caches peuvent imposer des droits d’écriture.

Le chemin le plus évident est wp-content/uploads. Il doit être écrivable par le serveur web. Mais il y a un sous-détail qui fait toute la différence : la façon dont PHP est interprété dans ce répertoire.

Dans une configuration saine, déposer un fichier PHP dans uploads ne devrait pas déclencher l’exécution. Cela dépend de la configuration serveur, par exemple une règle qui désactive l’interprétation PHP dans certains répertoires, ou une configuration qui associe PHP uniquement aux bons emplacements.

Ensuite viennent les dossiers qui peuvent changer selon votre setup :

    un cache disque si vous utilisez des plugins qui écrivent sur disque, certains dossiers de plugins ou thèmes lors d’opérations de mises à jour, parfois wp-content/upgrade pendant les mises à jour.

Le niveau d’attention doit être proportionnel aux chances que ces zones reçoivent des fichiers non maîtrisés. Les uploads sont évidemment en tête. Les caches aussi, selon leur usage. Le reste, en général, doit rester en lecture seule.

Cas typiques qui tournent mal

Les problèmes de permissions ne se manifestent pas toujours par une alerte claire. Souvent, vous voyez des symptômes indirects.

Un scénario fréquent sur des environnements “trop permissifs” : un dossier où les permissions permettent d’écrire, et où PHP est interprété. Une fois qu’un attaquant a trouvé un point d’entrée (par exemple une faille applicative ou un plugin vulnérable), il peut tenter d’écrire un fichier et de le faire exécuter. Parfois, il suffit d’un mauvais réglage sur un répertoire pour transformer une tentative en compromission durable.

Un autre scénario, à l’inverse : permissions trop restrictives. Le site charge partiellement, mais l’administration devient instable. Les mises à jour de WordPress échouent, l’ajout de médias plante, ou des pages renvoient un “erreur lors de la copie du fichier”. À ce stade, on se trompe souvent de cible, on débranche des plugins au hasard, puis on finit par relire les logs et réaliser que le serveur web n’a pas les droits sur un dossier précis.

Dans ces situations, le diagnostic passe souvent par deux questions simples :

    qui est l’utilisateur qui exécute PHP sur votre serveur ? quels dossiers WordPress tente d’écrire, au moment du problème ?

Sans ces réponses, on “bricole” les permissions. Et le bricolage, surtout en sécurité, coûte cher.

Le point de départ le plus fiable : vérifier l’utilisateur effectif du serveur web

Avant de modifier des droits, il faut savoir à qui ils doivent profiter. Le serveur web tourne sous un utilisateur système, et ce même utilisateur (ou un groupe) est ce qui doit avoir l’accès en écriture aux dossiers nécessaires.

Sur beaucoup de distributions Linux, le plus courant est www-data. Sur d’autres, c’est apache, ou un utilisateur dédié. Sur un hébergement mutualisé, l’accès est souvent abstrait, et on ne voit pas toujours le détail.

Si vous avez un accès shell, vous pouvez identifier l’utilisateur de service (via la configuration Nginx/Apache ou via les https://gardewp.fr/securite-wordpress/ processus en cours). Si vous n’avez pas de shell, passez par des indicateurs indirects, comme :

    erreurs mentionnant un chemin et un droit, capacité à écrire dans un dossier particulier, comportement lors des téléchargements.

Le but est de ne pas “ouvrir au monde entier”. Même si la configuration 777 peut sembler fonctionner, c’est exactement ce que vous ne voulez pas dans une démarche de renforcement sécurité WordPress.

Régler les permissions sans casser WordPress

Il y a une différence entre “casser WordPress” et “corriger les droits au bon endroit”. Dans la pratique, on évite les changements massifs et on cible les répertoires.

Les permissions recommandées varient, mais l’idée générale est cohérente :

    les fichiers PHP et les fichiers du code doivent être en lecture seule pour éviter toute modification involontaire, les dossiers doivent permettre la création et la modification là où c’est nécessaire, l’écriture ne doit pas être autorisée pour tout utilisateur “par défaut”.

Voici un cadre de vérification que j’utilise en atelier, simple, et assez robuste pour éviter les erreurs classiques :

    Vérifier que wp-content/uploads est inscriptible par le serveur web. Vérifier que les fichiers PHP du core, des thèmes et des plugins ne sont pas inscriptibles par un utilisateur non prévu. Vérifier que les dossiers de cache nécessaires sont inscriptibles, mais pas les autres. Vérifier que l’exécution PHP est limitée aux emplacements prévus par la configuration serveur. Tester un flux complet, uploads d’une image, mise à jour d’un plugin, régénération de cache, selon votre stack.

Cette approche évite deux erreurs fréquentes : changer “tout le répertoire” d’un coup, et ne valider que l’affichage public sans tester l’administration et les opérations d’écriture.

Exemple concret : durcir sans perdre l’accès à l’upload

Imaginons un site qui fonctionne, mais avec des permissions trop larges. Un administrateur décide de corriger en appliquant des droits stricts de type “lecture seule partout”. Résultat : plus aucune image ne s’ajoute. Dans les logs, on retrouve un message du style impossible d’écrire dans le répertoire de destination.

La correction n’est pas de revenir en arrière à un niveau complètement ouvert. Le chemin réaliste :

    garder des droits lisibles pour wp-content/uploads, rendre l’écriture disponible uniquement sur ce qui reçoit des fichiers, vérifier que la création de sous-dossiers fonctionne (WordPress crée des années et mois selon la structure), tester l’upload à nouveau.

À ce stade, vous voyez la logique : “sécurité” ne veut pas dire “zéro écriture”. Sécurité veut dire “écriture limitée”.

Exemple concret : le vrai sujet est parfois la configuration PHP, pas les chiffres

Parfois, le site est “sécurisé” en apparence sur les permissions, mais reste vulnérable parce que PHP est interprété dans des zones où il ne devrait pas l’être.

Supposez que wp-content/uploads soit écrivable et que PHP soit interprété dedans. Si un attaquant parvient à déposer un fichier avec extension ou contenu interprété, il peut tenter d’exécuter. Même si c’est une combinaison d’étapes, la configuration serveur peut augmenter ou réduire drastiquement le risque.

Dans une stratégie de renforcement sécurité WordPress, on ne s’arrête donc pas au système de fichiers. On s’assure aussi que l’exécution PHP est correctement bornée. Cela passe par :

    la configuration du serveur (directives Nginx ou règles Apache), éventuellement la désactivation de l’exécution dans certains répertoires, et des règles qui alignent interprétation PHP et emplacements attendus.

Dans beaucoup d’environnements, les hébergeurs appliquent déjà des protections. Mais dès qu’on migre, qu’on customise ou qu’on met en place un cache ou un reverse proxy, il faut vérifier que ces protections ne se sont pas inversées par accident.

Trade-offs : écrire partout pour “que ça marche”, ou verrouiller pour “réduire le risque”

Il existe un compromis pratique. Plus vous verrouillez, plus vous risquez de casser un plugin ou une fonctionnalité qui écrit sur disque.

Sur WordPress, les plugins ne sont pas tous du même acabit. Certains écrivent dans des répertoires de cache. D’autres modifient des fichiers de configuration. Certains gèrent des assets, des minifications, des traitements d’images. Même si vous avez une base saine, vous pourriez devoir adapter finement les permissions quand un plugin introduit une nouvelle zone d’écriture.

Ce qui marche bien en production, c’est une discipline :

    identifier les répertoires d’écriture réellement utilisés, limiter l’écriture à ces répertoires, garder le reste en lecture seule, documenter ce qui est autorisé et pourquoi.

J’ai vu des équipes sur un multi-site qui “ouvraient” trop large parce que “on ne sait pas ce que fait tel plugin”. En réalité, il y a toujours moyen de clarifier, en testant sur un environnement de préproduction et en observant les erreurs. Sans observation, on se prive d’un levier de sécurité très concret.

Comment diagnostiquer quand quelque chose casse

Quand une modification de droits échoue, WordPress peut répondre par des symptômes qui ne pointent pas directement vers les permissions.

Ce que je fais souvent :

    regarder les erreurs côté serveur (logs PHP-FPM, Nginx/Apache, ou logs application), repérer le chemin exact mentionné dans l’erreur, vérifier le propriétaire et le groupe du répertoire, vérifier l’existence des droits en écriture (et parfois l’exécution sur les dossiers quand nécessaire).

Les erreurs qui reviennent en boucle ressemblent souvent à “permission denied” ou “impossible de créer le répertoire”. Sans lire le chemin et le mode, vous risquez de corriger trop large.

À titre d’exemple, si le problème survient uniquement lors d’un upload, il y a de fortes chances que le dossier final, ou la capacité à créer des sous-dossiers, soit manquante. Si le problème survient lors d’une mise à jour, regardez wp-content/upgrade ou la capacité du serveur à écrire dans les emplacements de décompression.

Les erreurs classiques à éviter (et pourquoi elles sont dangereuses)

La sécurité n’est pas seulement ce qu’on fait, c’est aussi ce qu’on refuse de faire. Voici les pièges les plus fréquents que je rencontre lors d’audits, sur des sites qui ont tenté de “corriger” les permissions avant moi.

    Mettre 777 sur des répertoires de production, par réflexe. Donner un accès en écriture aux répertoires de code (plugins et thèmes) sans nécessité. Oublier la relation entre permissions et interprétation PHP (un dossier écrivable peut rester sûr, si PHP n’y est pas interprété). Modifier des permissions récursivement sans vérifier l’impact sur WordPress et les plugins d’optimisation ou de cache. Négliger l’utilisateur système exact qui exécute PHP, en supposant que “tout le monde” peut écrire.

Le point clé est la combinaison. Une permission seule peut être tolérable dans un contexte donné, mais dangereuse si un autre facteur s’y ajoute (interprétation PHP, écriture globale, absence de filtrage).

Une méthode d’approche graduelle, adaptée à un site en activité

Si vous travaillez sur un site déjà en ligne, l’approche la plus sûre évite les modifications lourdes d’un coup. Vous voulez réduire le risque d’indisponibilité tout en augmentant la sécurité.

Je procède généralement en trois phases :

Cadrage et observation, quels dossiers WordPress écrit réellement dans votre configuration, Durcissement ciblé, on réduit l’écriture et on aligne les droits sur le strict nécessaire, Validation fonctionnelle, pas seulement le rendu public, mais aussi l’administration et les actions qui écrivent.

La validation fonctionnelle est souvent ce qui manque. Un site peut afficher la home sans problème tout en cassant les uploads ou les mises à jour. Or, en sécurité comme en maintenance, ces opérations “d’écriture” sont précisément celles qui révèlent si une mauvaise permission vient de s’inviter.

image

image

Si vous utilisez un plugin de sécurité ou un WAF, rappelez-vous que ces couches ne remplacent pas les permissions. Elles limitent des attaques connues, mais elles n’empêchent pas une compromission si le serveur permet de faire exactement ce qu’un attaquant souhaite. Les permissions restent un rempart de base, et même quand tout est “verrouillé”, elles doivent rester cohérentes.

Et si vous n’avez pas accès aux réglages système ?

Sur certains hébergements, vous n’avez pas la main directe sur les permissions via shell. Vous pouvez parfois utiliser un panneau de contrôle, ou des paramètres fournis par l’hébergeur, et des recommandations.

Dans ce contexte, le bon réflexe n’est pas de deviner. Regardez :

    la documentation de votre hébergeur sur WordPress et PHP, les erreurs précises renvoyées lors des uploads ou des mises à jour, la capacité du site à créer des fichiers temporaires et des sous-dossiers.

Si l’hébergeur ne permet pas de maîtriser finement les permissions, le renforcement sécurité WordPress doit se déplacer vers d’autres leviers : durcissement serveur fourni, restrictions d’exécution, contrôles d’intégrité, mises à jour rapides, et durcissement côté application.

Cela ne veut pas dire “pas de permissions”. Cela veut dire “permissions hors de votre portée directe”. Votre rôle devient alors de vérifier que l’environnement fournit un modèle de permissions cohérent.

Comment rester cohérent dans le temps

Même si vous corrigez les permissions une fois, elles peuvent redevenir incorrectes après :

    une mise à jour de WordPress, un déploiement d’un thème ou d’un plugin, une migration, ou une action d’un plugin (réécriture, extraction, copie).

Pour tenir la sécurité dans le temps, je recommande de conserver une trace des changements et de tester régulièrement les opérations d’écriture. Un simple test périodique d’upload, plus une vérification que les mises à jour s’appliquent sans erreur, suffit souvent à révéler les dérives.

La cohérence, c’est aussi l’habitude de traiter WordPress comme un système de fichiers vivant, pas comme un dossier statique. Quand WordPress écrit, c’est normal. Quand WordPress (ou le serveur web) écrit là où il ne devrait pas, c’est là que les ennuis commencent.

Le bon niveau de “dureté” : une décision technique, pas une recette

Si je devais résumer mon approche de renforcement sécurité WordPress via les permissions PHP, ce serait ceci : vous choisissez la dureté en fonction de votre réalité, serveur par serveur, site par site.

    Sur un VPS, vous pouvez aligner proprement propriétaire, groupe et droits, et tester finement. Sur un mutualisé, vous devez respecter les contraintes de l’hébergeur et travailler avec ce que vous pouvez contrôler. Sur un environnement avec cache et reverse proxy, vous devez vérifier que les dossiers autorisés à recevoir des fichiers ne sont pas interprétés de manière imprévue.

Ce n’est pas la même chose de “fermer” et de “verrouiller”. Un verrouillage utile réduit la surface d’attaque, il ne casse pas les fonctions normales. Quand ça casse, ce n’est pas forcément mauvais, ça peut révéler un droit manquant. Mais quand ça “fonctionne” en autorisant trop, là, vous créez un risque latent.

image

Les permissions sont parfois invisibles, jusqu’au jour où elles deviennent le facteur décisif. En gérant correctement les permissions PHP et les droits d’écriture, vous posez une base solide, souvent sous-estimée, mais très efficace pour limiter les dégâts en cas d’incident.

Si vous voulez, décrivez votre configuration (Nginx ou Apache, accès shell oui ou non, et quelques chemins comme wp-content/uploads et les dossiers de cache utilisés). Je peux vous proposer une approche plus ciblée, orientée sur votre situation plutôt que sur une valeur générique.