Permissions des fichiers WordPress : 644, 755 et propriétaire
Permissions des fichiers WordPress : sens de 755 et 644, bon propriétaire, commandes de réinitialisation sûres et pourquoi 777 ne règle jamais une erreur d'upload.
Aussi en : English Deutsch Español Italiano Polski Português Türkçe
Permissions des fichiers WordPress : la valeur sûre en un paragraphe
Pour les permissions des fichiers WordPress, la valeur sûre est 755 pour les répertoires, 644 pour les fichiers, et un 640 ou 600 plus strict pour wp-config.php. Jamais de 777. Ces chiffres ne vous protègent toutefois que si le bon utilisateur est propriétaire des fichiers. Un 644 parfait sur des fichiers appartenant au mauvais compte bloque les envois et les mises à jour, ou bien donne discrètement au serveur web plus de pouvoir que nécessaire. Lisez donc la section sur le propriétaire avant de modifier le moindre mode.
Propriétaire, groupe et autres : lire 755 et 644
Lancez ls -l à la racine de WordPress et vous obtenez des lignes comme celles-ci :
drwxr-xr-x 5 deploy www-data 4096 Oct 30 09:12 wp-content
-rw-r--r-- 1 deploy www-data 405 Oct 30 09:12 index.php
-rw-r----- 1 deploy www-data 3214 Oct 30 09:12 wp-config.php
Le premier caractère indique le type (d pour un répertoire, - pour un fichier). Viennent ensuite trois groupes de trois lettres : un pour le propriétaire (deploy), un pour le groupe (www-data) et un pour tous les autres. r signifie lecture (read), w écriture (write) et x exécution (execute). Chaque lettre a une valeur : r = 4, w = 2, x = 1. Additionnez-les pour chaque groupe et vous obtenez le mode octal : rwxr-xr-x devient 7-5-5.
Sur un répertoire, x signifie « a le droit d'y entrer ». Sans lui, PHP ne peut pas ouvrir les fichiers qu'il contient, même s'ils sont lisibles. C'est pourquoi les répertoires demandent 755 et les fichiers seulement 644. Dans une installation WordPress normale, aucun fichier n'a besoin du bit d'exécution.
| Mode | Lettres | Usage typique |
|---|---|---|
| 755 | rwxr-xr-x | Répertoires |
| 644 | rw-r--r-- | Fichiers ordinaires |
| 640 | rw-r----- | wp-config.php, utilisateur PHP dans le groupe |
| 600 | rw------- | wp-config.php, utilisateur PHP propriétaire |
Le propriétaire compte autant que le mode
Commencez par déterminer sous quel utilisateur PHP s'exécute. Sur votre propre serveur, examinez les processus en cours :
ps -eo user,comm | grep -E 'php-fpm|apache2|httpd' | sort | uniq
Avec PHP-FPM, le processus maître tourne en root et les workers sous l'utilisateur du pool. C'est le fichier du pool qui définit cet utilisateur. Sous Debian et Ubuntu, il se trouve généralement dans /etc/php/<version>/fpm/pool.d/ :
grep -R -E '^(user|group) *=' /etc/php/*/fpm/pool.d/
La documentation de configuration de PHP-FPM décrit ces paramètres. Avec Apache et mod_php, PHP s'exécute sous l'utilisateur d'Apache lui-même : www-data sous Debian/Ubuntu, apache sur les systèmes de la famille RHEL. Tous les sites du serveur partagent alors une seule identité. Un bon hébergement mutualisé isole au contraire les sites : le PHP de chaque compte tourne sous l'utilisateur propre à ce compte. Si vous ne pouvez pas lancer ps, ouvrez Outils > Santé du site > Info > Permissions du système de fichiers (Filesystem Permissions). Vous y voyez si WordPress peut écrire dans son répertoire principal, dans wp-content, dans uploads, dans les extensions et dans les thèmes.
Une fois l'utilisateur PHP identifié, choisissez l'un des deux modèles de propriété.
Modèle A : l'utilisateur PHP possède tout. C'est le cas typique d'un hébergement mutualisé isolé, où l'utilisateur de votre compte et l'utilisateur PHP sont les mêmes. Les mises à jour depuis le tableau de bord, l'installation d'extensions et les envois de fichiers fonctionnent. Contrepartie : tout code exécuté sous PHP peut aussi réécrire n'importe quel fichier, y compris le cœur, les extensions et wp-config.php.
Modèle B : un utilisateur de déploiement possède les fichiers, PHP ne fait que lire. Les fichiers appartiennent à quelque chose comme deploy:www-data, en 755/644. PHP peut tout lire, mais n'écrit que là où vous l'autorisez : wp-content/uploads et les éventuels répertoires de cache. Vous mettez alors à jour avec WP-CLI ou en SFTP sous l'utilisateur de déploiement, pas depuis le tableau de bord. Les dégâts possibles sont limités, mais cela demande plus de travail. Si vous voulez en plus verrouiller définitivement le tableau de bord, voyez DISALLOW_FILE_MODS et ses compromis.
Le modèle B explique une énigme fréquente : WordPress qui réclame des identifiants FTP quand vous cliquez sur « Mettre à jour ». WordPress vérifie si les fichiers qu'il crée auraient le même propriétaire que ses propres fichiers. Si ce n'est pas le cas, il se rabat sur FTP. Forcer FS_METHOD à direct masque le symptôme sans traiter la cause. Décidez quel modèle vous voulez, puis alignez le propriétaire dessus.
Réinitialiser les permissions WordPress en toute sécurité
Faites d'abord une sauvegarde des fichiers et de la base de données. Placez-vous ensuite à la racine de WordPress et vérifiez que vous êtes au bon endroit :
cd /var/www/example.com/public
ls wp-config.php
Si ls ne trouve pas wp-config.php, arrêtez-vous. (Certaines installations le placent un niveau au-dessus de la racine web : vérifiez donc votre arborescence.) Réinitialisez ensuite les modes :
find . -type d -exec chmod 755 {} \;
find . -type f -exec chmod 644 {} \;
Sur les gros sites, la variante avec + est nettement plus rapide, car elle transmet de nombreux fichiers à chaque appel de chmod :
find . -type d -exec chmod 755 {} +
find . -type f -exec chmod 644 {} +
Ne changez le propriétaire que sur un serveur que vous maîtrisez. Pour le modèle B, cela donne :
sudo chown -R deploy:www-data /var/www/example.com/public
La réinitialisation écrase aussi les exceptions ci-dessous : réappliquez-les tout de suite. Vérifiez ensuite le résultat avec stat -c '%a %U:%G %n' wp-config.php wp-content/uploads, envoyez une image de test et chargez quelques pages.
Exceptions : wp-config.php, uploads et .htaccess
wp-config.php contient le mot de passe de votre base de données : la catégorie « autres » ne doit donc rien recevoir. Utilisez 600 si l'utilisateur PHP est propriétaire du fichier (modèle A). Utilisez 640 si c'est un utilisateur de déploiement qui en est propriétaire et que PHP le lit via le groupe (modèle B). Avec 600 dans le modèle B, PHP ne peut pas lire le fichier et le site tombe. Pour les clés secrètes (salts), les réglages de débogage et les copies de sauvegarde oubliées, voyez le durcissement de wp-config.php.
wp-content/uploads et les répertoires de cache doivent être accessibles en écriture à l'utilisateur PHP. Dans le modèle B, soit vous faites de l'utilisateur PHP le propriétaire de ces répertoires, soit vous les laissez au groupe PHP avec écriture pour le groupe (775 pour les répertoires, 664 pour les fichiers). Limitez l'écriture à ces chemins, pas à tout wp-content.
Sous Apache, .htaccess est un cas particulier. S'il est modifiable, WordPress met à jour les règles de réécriture quand vous enregistrez les permaliens, et les extensions de cache ou de sécurité y ajoutent leurs propres blocs. S'il ne l'est pas, WordPress affiche les règles à coller à la main. Un .htaccess en lecture seule coûte un peu de confort. En échange, du code exécuté sous PHP ne peut pas y glisser une redirection ou une ligne auto_prepend_file.
Pourquoi 777 ne corrige jamais une erreur d'envoi
777 autorise tous les comptes et tous les processus du serveur à écrire dans le fichier ou le répertoire. Sur un hébergement mutualisé, cela peut inclure les scripts compromis d'autres clients. L'erreur d'envoi peut disparaître, mais uniquement parce que la protection saute, pas parce que la cause est corrigée. Cherchez les vraies causes dans cet ordre :
- Mauvais propriétaire. Le message « Unable to create directory wp-content/uploads/… Is its parent directory writable by the server? » signifie presque toujours que l'utilisateur PHP n'est pas propriétaire de uploads, ou ne peut pas y écrire. Cela arrive souvent après une migration ou une restauration faite en root.
- Disque ou quota plein. Lancez
df -hsur votre propre serveur, ou consultez le quota dans le panneau de votre hébergeur. - Répertoire temporaire ou limites de chemins. « Missing a temporary folder » renvoie à
upload_tmp_dir. Une restrictionopen_basedirqui exclut le chemin temporaire peut aussi bloquer les envois. - Limites de taille. « The uploaded file exceeds the upload_max_filesize directive » signifie qu'il faut augmenter
upload_max_filesizeetpost_max_size, ou envoyer un fichier plus léger.
Sur un hébergement mutualisé, vous ne pouvez généralement pas lancer chown vous-même. Demandez à votre hébergeur de rétablir le bon utilisateur comme propriétaire des fichiers de votre compte. C'est une demande courante.
Ce que de bonnes permissions ne protègent pas
Les permissions limitent ce qu'un utilisateur peut faire. Elles ne font rien contre du code qui s'exécute déjà sous cet utilisateur. Si une extension vulnérable permet à un attaquant d'exécuter du PHP, son code dispose des droits de l'utilisateur PHP. Dans le modèle A, cela veut dire tout. Dans le modèle B, cela couvre encore uploads, les répertoires de cache et tout ce que vous avez rendu inscriptible. C'est pourquoi les attaquants affectionnent uploads, comme l'explique l'article sur les web shells dans wp-content/uploads.
Réinitialiser les permissions après un piratage ne supprime pas non plus une porte dérobée. Le fichier malveillant est toujours là, simplement avec des modes bien rangés. Suivez d'abord un vrai plan de nettoyage des malwares, puis corrigez les permissions dans l'étape de durcissement. Au regard du RGPD, des permissions correctes peuvent compter parmi les mesures techniques qui protègent l'intégrité et la confidentialité des données personnelles (art. 32, EUR-Lex), mais elles n'ont de valeur que dans un ensemble de mesures plus large.
Vérifier régulièrement les permissions
Les permissions finissent par dériver. Les causes habituelles : migrations, restaurations de sauvegarde, changements d'hébergeur et un correctif rapide fait avec sudo. Lancez ces deux contrôles à la racine de WordPress après chacun de ces événements, et de toute façon tous les quelques mois :
find . -perm -o+w ! -type l
find . ! -user deploy
La première commande liste tout ce qui est modifiable par n'importe qui (les liens symboliques sont exclus, car ils s'affichent toujours en 777). La seconde liste les fichiers dont le propriétaire n'est pas celui attendu. Dans le modèle A, remplacez deploy par votre utilisateur PHP. Les deux commandes ne doivent rien renvoyer, ou seulement des chemins que vous savez expliquer. Le guide des permissions de fichiers de WordPress.org décrit la même base, du côté de l'équipe du cœur.
Pour garder une vue d'ensemble, le plugin Security Audit & Compliance de secaudit.eu effectue des contrôles de durcissement et de configuration, ainsi qu'une surveillance de l'intégrité des fichiers : les fichiers modifiés ou nouveaux apparaissent entre deux revues manuelles → secaudit.eu
FAQ
wp-config.php doit-il être en 400 ou en 440 ?
C'est possible aussi, à condition que PHP puisse toujours lire le fichier : 400 si PHP en est propriétaire, 440 si PHP le lit via le groupe. L'inconvénient : il faudra rétablir le mode avant de modifier le fichier. 600 ou 640 est le compromis habituel.
755/644 est-il sûr sur un hébergement mutualisé ?
Oui, si l'hébergeur isole les comptes de sorte que votre PHP s'exécute sous votre propre utilisateur. Avec 644, d'autres comptes pourraient techniquement lire vos fichiers. C'est l'isolation qui l'empêche : la configuration de votre hébergeur compte donc plus que les chiffres.
Faut-il réinitialiser les permissions après chaque mise à jour ?
Non. WordPress crée les nouveaux fichiers avec des modes adaptés. Lancez plutôt les contrôles ci-dessus, et ne réinitialisez que s'ils révèlent des problèmes.
Vérifiez votre propre site
Security Audit & Compliance est l’extension WordPress de secaudit.eu : elle recherche les logiciels malveillants, le spam caché, les fichiers du cœur modifiés et le code vulnérable, et rattache ses constats à l’article 32 du RGPD, à l’article 21 de NIS2 et à l’OWASP Top 10.
Voir ce que vérifie l’extension