Chapitre 8 sur 20

Sécuriser WordPress

Laisser un commentaire

De très nombreux WordPress se font hacker, c’est un fait. D’ailleurs, de très nombreux sites se font hacker, et comme WP une grosse part de marché, forcément, statistiquement, ils font partie du lot.

Pour autant, on ne peut pas vraiement accuser WordPress. En effet, 99,999% du temps, la faute vient d’un site mal configuré, non mis à jour, ou de plugins choisis à la légère. Voyons les différents moyens à notre disposition pour mitiger tout cela.

Bien choisir ses plugins

C’est la base, WordPress en lui-même est assez bien sécurisé, et lorsqu’il ne l’est pas, c’est à dire qu’une faille est découverte, elle est corrigée extrêmement rapdiement et mise à disposition de tous.

Le core est géré par de nombreux développeurs professionnels et supporté par une entreprise. Ce n’est pas forcément le cas pour les plugins, dont certains sont plus ou moins abandonnés par leurs créateurs. Avant d’installer un plugin, regardez s’il a été testé avec votre version de WordPress, combien d’installations WordPress l’utilisent et la date de sa dernière mise à jour.

Par ailleurs, vous pouvez vous renseigner sur l’auteur du plugin. Le nombre d’autres plugins qu’il édite, si les autres plugins sont maintenus, s’il s’agit d’une société ou d’un développeur seul… En dernier lieu, vous pouvez jeter un œil au code. Sans avoir besoin de réaliser un audit complet, la structure et le style (ou leur absence) du code est parfois rapidement évocateur.

Comme les modules npm ou les bundle Symfony, il n’y a pas de technique infaillible pour choisir les bons plugins. Cependant, ces indicateurs vous permettront de vous faire une idée de leur fiabilité. Par ailleurs, ce n’est pas parce qu’un plugin est payant qu’il est de qualité…

… et ses mots de passe

Sans surprise, admin/admin, c’est risqué ! Et pourtant, même sur des sites d’envergures, combien de hacks sont liés à des mots de passe trop faibles ? Par pitié, utilisez un générateur de mot de passe si vous manquez de créativité et demandez à votre navigateur ou un logiciel de gestion de mot de passe de s’en souvenir pour vous.

Pensez aussi à ne pas utiliser “admin” pour le compte par défaut. En outre, faites en sorte que le login et le votre nom d’utilisateur diffèrent – surtout s’il est publiquement affiché sur le site (auteur des articles de blog par exemple). Pour cela, vous pouvez attribuer un pseudonyme à votre compte : utilisateur –> votre profil –> pseudonyme.

Enfin, afin d’éviter les attaques par brute-force, on peut bloquer tout utilisateur testant plus de X mots de passe dans un laps de temps donné. J’utilise pour cela le très bon Login LockDown.

Se prémunir du CSRF

Le CSRF est une faille de sécurité assez simple mais très efficace.

L’objet de cette attaque est de transmettre à un utilisateur authentifié une requête HTTP falsifiée qui pointe sur une action interne au site, afin qu’il l’exécute sans en avoir conscience et en utilisant ses propres droits. L’utilisateur devient donc complice d’une attaque sans même s’en rendre compte. L’attaque étant actionnée par l’utilisateur, un grand nombre de systèmes d’authentification sont contournés.

WikiPedia

WordPress met à disposition du développeur son système de nonces. Ce système permet de déjouer les attaques CSRF en s’assurant que la requête provient bien de la session courante.

Les nonces WordPress consistent en un système de token à durée limitée. Vous pouvez les utiliser pour protéger les url, les formulaires et les requêtes Ajax. Dès lors que vous traitez des données soumises par l’utilisateur (formulaires, commentaire, action du compte client…), il est recommandé de les sécuriser par des nonces.

Voici par exemple comment vous placez un nonce dans un formulaire.

<form method="post">
    <input type="text" name="exemple" placeholder="Un input d'exemple">
    <?php wp_nonce_field(); ?>
</form>

Et vous le vérifiez ensuite avant d’exécuter votre action.

if (wp_verify_nonce($_POST['_wpnonce']) === 1) {
    // tout est ok, on peut continuer
}

else {
    // le nonce n'est pas valide, vous pouvez envoyer un message d'erreur
}

Je vous recommande la lecture de la documentation des nonces pour découvrir comment sécuriser vos URL et vos actions Ajax.

Désactiver les modifs de code via l’UI

Si un attaquant arrive à se connecter en tant qu’utilisateur, on peut lui compliquer la tâche. Dans la plupart des cas, la fonctionnalité “Éditeur” qui se trouve dans le menu “Apparence”, ne sert à rien. On peut donc la désactiver via une ligne dans le wp-config.php.

define('DISALLOW_FILE_EDIT', true);

L’accès à cette fonction lui permettrait de facilement ajouter un code malicieux : envoyer du spam, récupérer les informations de votre base de données…

On peut même aller bien plus loin : tout est géré directement par le développeur, on indique donc à WordPress ne rien modifier sur le serveur (en dehors de médias et autres éléments nécessaires à son fonctionnement normal).

define('DISALLOW_FILE_MODS', true);

Si vous utilisez Steroids, ces deux options sont activables directement via le .env.

DISALLOW_FILE_EDIT=true
DISALLOW_FILE_MODS=true

Garder WordPress à jour

Comme tout logiciel open source, les failles des anciennes versions de WordPress sont publiques et connues, il est donc important de faire les mises à jour de sécurité du CMS et des plugins, de la même manière que vous le feriez avec les dépendances de n’importe quel projet web.

Dans le cas d’une installation classique, WordPress permet d’automatiser les mises à jour. Pour cela, tout se passe dans wp-config.php.

// autoriser toutes les maj auto (majeures et mineures)
define('WP_AUTO_UPDATE_CORE', true);

// automatiser seulement les maj mineures
define('WP_AUTO_UPDATE_CORE', 'minor');

// et pour tout interdire
define('WP_AUTO_UPDATE_CORE', false);

Et pour les mises à jour des plugins et des thèmes (non pertinent si le thème est développé sur-mesure).

// active les maj des plugins
add_filter('auto_update_plugin', '__return_true');

// active les maj des thèmes
add_filter('auto_update_theme', '__return_true');

Toutes les mises à jour ne concernent pas des correctifs de sécurité. Par ailleurs, plus un site est d’envergure et repose sur des interractions complexes avec des plugins, plus il est susceptible de rencontrer des problèmes lors de mises à jour. Pour cette raison, il n’est pas toujours recommandé d’activer les mises à jour automatiques.

Dans le cas d’un petit site, on peut s’en tirer sans problème avec les mises à jour auto. Pour un site un peu plus conséquent, on peut se contenter des mises à jour de WordPress (voir les mises à jour mineur pour les plus frileux).

La petite histoire

J’ai récemment eu quelques développements à effectuer sur un site créé pour un client il y a plus de 8 ans. Mes pratiques de code ont indéniablement évolué depuis (ça fait toujours mal de regarder du vieux code).

Cependant, le site étant simple et plutôt bien conçu, RAS avec les mises à jour auto en 8 ans. J’ai même pu le passer sous PHP 8 sans aucun problème. 🎉

Dans le cas où l’on veut gérer les mises à jour de plugins manuellement, le but est d’effectuer les mises à jour de sécurité et de ne pas perdre du temps avec les autres mises à jour (car il y en a constamment). Dans cette optique, j’affectionne particulièrement WPscan.

Exemple d'un avertissement WPScan

Il s’agit d’une base de données qui recense les vulnérabilités connues du core, des plugins et des thèmes. Ils proposent aussi un plugin permettant de scanner périodiquement l’installation et de vous avertir en cas de problème.

En outre, si votre projet est hébergé sur GitHub, il est possible de configurer Dependabot pour automatiquement effectuer les mises à jour. Il suffit pour d’activer Dependabot dans les paramètres du projet.

Pour ceux n’utilisant pas GitHub, sachez que GitLab offre également le dependency scanning dans sa version Ultimate et que cette fonction est intégrée dans l’offre de Snyk.io. Ce dernier, ainsi que Dependaroo profitent d’ailleurs d’une intégration poussée avec Bitbucket.

Pour en revenir à Dependabot, sachez néanmoins qu’il s’agit d’un logiciel open source et qu’il est donc disponible pour tous. À ce titre, il est possible de l’intégrer à GitLab par exemple. Si cela vous intéresse, je vous conseille la lecture de cet article [en].

Bien régler les droits

La bonne gestion des droits des fichiers et répertoires a une incidence directe sur la sécurisation de votre installation. Si tout utilisateur peut créer, modifier et exécuter les fichiers, vous imaginez bien que c’est yolo ! D’ailleurs, si les droits des fichiers – alias chmod – et la gestion des utilisateurs ne vous parlent pas trop, lisez mon court article sur le sujet.

WordPress donne quelques indications pour le bon réglage des permissions. Une fois n’est pas coutume, tout va dépendre de notre usage de WP.

Dans son usage le plus classique, le CMS a besoin des autorisations en lecture/écriture sur à peu près tout. En effet, sans ces autorisations, il ne peut pas lui-même procéder à ses mises à jour, gérer les plugins, les thèmes…

mise à jour en erreur
WordPress ne peut plus se mettre lui-même à jour avec des droits restrictifs

Si l’on veut préserver toutes ces possibilités, il faudra que l’utilisateur exécutant le serveur (www, www-data, apache, nobody… pour les noms courants) possèdent des droits en écriture. On a donc en général le propriétaie qui possède tous les droits (utilisateur du compte SSH ou FTP), puis le groupe, dont fait partie le serveur web, qui possède des droits plus restreints, enfin les droits pour les autres utilisateurs.

À chacun sa config

À moins que vous n’utilisiez un serveur dédié (ou virtuel), chaque hébergeur possède sa propre configuration d’utilisateurs et de groupes. Par exemple, sur certains sites que je gère qui sont sur des serveurs dédiés, le propriétaire est root, le superadmin du serveur. Si je donne au groupe du serveur web uniquement des droits en lecture, WordPress ne pourra pas effectuer ses updates tout seul.

En revanche, chez la plupart des hébergeurs cloud et mutualisés, l’utilisateur SSH (ou FTP) est le même que l’utilisateur qui exécute PHP. Donc si je suis propriétaire des fichiers et répertoires, alors PHP peut également les modifier. Ça facilite la gestion des droits, mais c’est moins sécurisé.

Une config générale mais somme toute assez propre consiste à placer l’utilisateur SSH/FTP comme popriétaire et groupe et seulement l’utilisateur du serveur comme groupe du wp-content. Ensuite, tous les fichiers sont en 644 et les répertoires en 755 (on pourrait même dire 640 et 750).

chown -R admin:admin wordpress
chown -R admin:webserver wordpress/wp-content

find wordpress -type d -exec chmod 755 {} \;
find wordpress type f -exec chmod 644 {} \;

Évidemment, si votre configuration utilise un compte différent de votre compte utilisateur pour PHP et que vous souhaitez laisser WordPress gérer les mises à jour, on pourra placer l’utilisateur serveur en groupe et lui attribuer les droits d’écriture.

chown -R admin:webserver wordpress

find wordpress -type d -exec chmod 755 {} \;
find wordpress type f -exec chmod 666 {} \;

Correctement configurer la BDD

De la même manière que les droits des fichiers, les droits de l’utilisateur sur la base de données peut mener à de sérieux problèmes s’ils sont mal configurés. Par exemple, ce que l’on utilise en dev – l’utilisateur root pour accéder à la base de WorPress sans mot de passe, c’est totalement interdit en prod.

Dans son fonctionnement courant, WP n’a besoin que de SELECT, UPDATE et DELETE sur les tables de sa base de données. Cependant, lors de l’installation de certains plugins ou de mises à jour, il lui faudra potentiellement DROP, ALTER et GRANT.

De ce fait, comme nous n’allons pas nous amuser à modifier les permissions de l’utilisateur MySQL avant chaque update, on effectue en général un compromis et on accorde tous les droits sur sa base (et pas sur les éventuelles autres bases de MySQL !).

# droits classiques
GRANT ALL PRIVILEGES ON `base_du_site`.* TO 'user'@'localhost';

# droits plus restreints
# risque de ne pas fonctionner via la web interface certaines opérations
GRANT SELECT, UPDATE, DELETE ON `base_du_site`.* TO 'user'@'localhost';

Dans le cas où on désactive les updates et l’installation de plugins via la UI de WordPress, on pourrait utiliser des droits restreints et posséder un autre utilisateur réservé aux opérations d’administration, lequel serait exclusivement utilisé par la CLI.

Chouchouter les fichiers sensibles

La plupart des informations sensibles sont bien protégées :

# Pensez quand même à désactiver le listing des répertoires dans le .htaccess
Options All -Indexes

WordPress, contrairement à d’autres frameworks, place tout le code dans le répertoire public. Ceci est dû à des raisons historiques, cependant, cela expose l’ensemble des fichiers car ils peuvent être directement requêtés via leur url : http://mon-site.net/wp-config.php.

Il en va évidemment de même pour tous les fichiers du thème. Comme le code contenu dans ces fichiers ne s’attend pas à être invoqué directement – il dépend de variables et fonctions déclarées ailleurs dans WordPress mais qui n’existent pas lors d’une invocation directe – évidemment, cela provoque des erreurs.

C’est pour cela que j’insiste dans la partie Conventions de code sur le test de l’ABSPATH en haut de chaque fichier.

defined('ABSPATH') || exit;

Nous avons maintenant une bonne base de sécurité, mais gardez tout de même à l’esprit que rien n’est jamais 100% sécurisé. Des institutions d’importance comme le FBI, la NSA ou le ministère de la Défense française ont déjà toutes essuyé des piratages, personne n’est donc jamais vraiment à l’abris d’une faille ou d’une erreur.

Dans le prochain chapitre, nous allons aborder un autre sujet d’importance : les taxonomies.

Commentaires

Rejoignez la discussion !

Vous pouvez utiliser Markdown pour les liens [ancre de lien](url), la mise en *italique* et en **gras**. Enfin pour le code, vous pouvez utiliser la syntaxe `inline` et la syntaxe bloc

```
ceci est un bloc
de code
```