Sécurité WordPress : 13 recommandations et 1 mythe

14 Mai 2018

Salut !

Voici un petit topo débutant sur la protection d’un site WordPress. J’avoue, il n’y a rien de moi dans cet article, mais à force de glaner des infos çà et là, je me suis dit que j’allais les vérifier et les regrouper dans un post.

Je parle ici de sécurité basique ; je me limite donc à des recommandations simples, faisant appel au bon sens, et à quelques lignes de code permettant de combler certaines lacunes des installations WordPress, à inclure dans les fichiers .htaccess (directives serveur Apache) et functions.php (votre thème enfant WordPress).

Aucun de mes sites ne semble avoir été piraté et je n’ai jamais rien détecté d’anormal dans mes logs ou fichiers, donc je considère pour le moment que les éléments ci-dessous sont suffisants pour leur contenu et leur (faible) trafic. Ce n’est peut-être pas la même histoire pour des cibles plus exposées et/ou contenant des informations plus convoitées comme des coordonnées bancaires.

Dans l’énumération qui suit, je commence par les conseils les plus élémentaires, d’ordre général, puis je continue avec des mesures plus spécifiques et plus techniques (même si dans la pratique ça reste du copier/coller…). Prêts ? Alors c’est parti !

Ne jamais se croire à l’abri des attaques

Les attaques de site WordPress n’ont rien de personnel ; ce sont des attaques systématiques effectuées par des scripts automatisés (bots ou botnets). Les motivations de ces attaques sont variées, par exemple utiliser votre bande passante, rediriger du trafic, transformer votre machine en passerelle, envoyer du spam…

Ne pensez donc surtout pas que votre « simple blog » n’a aucun intérêt à être piraté… TOUS LES SITES WORDPRESS sont des cibles !

Terminer tout de suite l’installation de WordPress

Cette consigne vous paraitra peut-être étrange, mais si vous copiez les fichiers de WordPress sur votre hébergement sans lancer l’installation (ou en l’abandonnant en cours), le système se trouve dans un état très vulnérable, puisque le fichier /wp-admin/setup-config.php est librement accessible.

Or, des robots scannent les URLs à la recherche de ce fichier afin de réaliser eux-même l’installation et implanter un back door avant de vous rendre le site dans l’état initial.

Si vous vous demandez par quel miracle ils sont au courant de votre installation, découvrez comment les hackers trouvent votre site avant même que vous l’ayez installé.

Choisir des mots de passe sûrs

Choisissez des mots de passe compliqués pour les pirates mais pas trop pour vous :

  • Un mot de passe différent sur chaque site permet de ne pas mettre tous ses œufs dans le même panier.
  • Plus le mot de passe est long, plus il sera long à déchiffrer. Aujourd’hui, au delà d’une douzaine de caractères, il faut plusieurs années pour déchiffrer un mot de passe avec un ordinateur classique, donc une longueur entre 15 et 20 sera bien suffisante (il y a peu de chances que vous soyez attaqué par un CRAY…).
  • L’ajout de majuscules, chiffres et caractères spéciaux augmente encore la complexité du déchiffrage.
  • L’utilisation de mots du dictionnaire est évidemment à proscrire, car le mot de passe serait découvert immédiatement ou en quelques minutes maximum.
  • Une phrase ou expression peut être très facile à mémoriser mais très complexe à déchiffrer. Attention, à personnaliser quand même pour chaque site, et toujours avec chiffres, majuscules et caractères spéciaux.

A titre indicatif, vous pouvez vérifier la complexité de votre mot de passe.

Choisir un identifiant administrateur sûr

Ne JAMAIS utiliser l’identifiant « admin » pour l’administrateur du site. Ni aucun identifiant trop évident comme « root », le nom du site, votre nom, etc.

Ça faciliterait beaucoup trop le travail des pirates et des botnet et de leurs attaques par force brute. Ajoutons-leur donc un peu de difficulté en camouflant l’accès le plus sensible.

Maintenir votre système à jour

Mettre à jour son installation WordPress régulièrement n’est malheureusement pas un réflexe pour tout le monde, y compris chez les professionnels du web. C’est pourtant le seul moyen de supprimer les failles, publiques ou non, exploitées par les hackeurs.

Personnellement, j’attends parfois quelques jours, voire semaines, pour des grosses mises à jour de WordPress ou de thèmes quand je lis ou sens qu’elles sont potentiellement à risque… Je consulte les forums pour voir s’il y a des retours, des patchs, etc, avant de basculer.

Mais la plupart du temps je le fais dès que je vois une notification, en particulier pour les plugins, Y COMPRIS LES PLUGINS INACTIFS, dont le code peut être exécuté, et donc les failles exploitées.

Remarque : Au -delà de l’aspect sécurité, c’est aussi un énorme gain de temps de maintenance par rapport à des mises à jour plus espacées, qui sont beaucoup plus difficiles à débugguer quand ça se passe mal (et statistiquement, en attendant plusieurs mois, ça se passe souvent mal).

Effectuer des sauvegardes régulières

Puisque la sécurité d’un système n’est jamais garantie à 100%, la sauvegarde régulière reste la seule pratique vous assurant de ne pas perdre du contenu. A stocker dans plusieurs endroits (disque externe, cloud, clé…) pour réduire les risques au « presque » zéro absolu.

Vérifier la provenance des thèmes ou extensions

Sans vouloir faire dans la paranoïa, il est toujours plus prudent de se renseigner sur les logiciels qu’on veut installer, que ce soit sur un ordinateur ou sur un site.

Les thèmes avec pignon sur rue et moult avis positifs sont évidemment a priori plus sûrs qu’un plugin craqué ou un thème gratuit trouvé sur des sites plus ou moins obscurs, parfaits vecteurs de propagation de virus ou plus généralement de malwares.

De plus, même si c’est rare, certains thèmes ou plugins bâclés et/ou buggés peuvent tout simplement corrompre votre installation sans pour autant avoir d’intension malfaisante. Dans le doute, effectuez une sauvegarde avant de tester quoi que ce soit.

Renseigner les clés de sécurité et le salage

Les secret keys du fichier config.php (situé à la racine de votre site) sont des clés de « hash » utilisées par WordPress pour crypter les mots de passe en base de données et les informations contenues dans ses cookies, incluant identifiant et mot de passe de l’utilisateur.

Le « sel », constitué du même nombre de clés supplémentaires (de suffixe _SALT), a été ajouté pour complexifier encore le décryptage des hash générés.

Exemple de clés de sécurité :

define('AUTH_KEY',         ']T_4Nsg#nF]EqrdOr~d4OBZNOgm_a(<<d,a>wR]WIYu]%a+?/}TMUSKF(vs1[Q6*');
define('SECURE_AUTH_KEY',  'nZIES6@lmU;u9H>-p}Q_gi.Wc/JRREMxc1p!${[||_8tW%jSUw3FW$P+:VaA&UA<');
define('LOGGED_IN_KEY',    'cnp$A1D+xSREH0z%omm=p-,+RfYRYN]<`h8unv6)vOB-jp`%$D#X~{S|e>vyAjV3');
define('NONCE_KEY',        'Pu_;II4^4cF{KQ8b)=|BW2s+)Oyt7CndzPXyE~$#2@qs/>ts@T @$-_lZ {N,^yv');
define('AUTH_SALT',        'bI5VoBw65an{+}4j,_-[p=5cYaexs6FPIJSNteG[A~F;UJ!f^&T1wjyFC2CGP:qH');
define('SECURE_AUTH_SALT', '9v@HSUWaHZ142&]aTltLEtJc8& D>G6yj-=0lZf.9X!9m9d:L_H}=O^aq`boL)*9');
define('LOGGED_IN_SALT',   'te&SX/K-C}GkGQvy~f+gI-h0WE9G*2tkT)o]g-Id(>kM3AX^n``vX0Ks|:,8JZ?+');
define('NONCE_SALT',       '(fO8D+SLtD+4nC&5&KJy~07_;21~&P_M@/=(-J@~/[zt&p!eE-8KT4wf`GCQ?+,|');

Ces clés doivent être renseignées dans le fichier config.php, car sinon WordPress en génère automatiquement, mais les stocke en base de données, donc au même endroit que les mots de passe, ce qui facilite le déchiffrage de ces derniers.

Si ce n’est pas le cas, utilisez ce générateur de clés fourni par WordPress et copiez le résultat dans votre fichier.

Vous pourrez également renouveler ces clés pour invalider tous les cookies qui n’ont pas encore expiré ou par simple mesure de précaution, de la même façon que vous devriez changer tous vos mots de passe régulièrement au cas où des fichiers se seraient un jour perdus dans la nature (ça arrive aux plus grosses boîtes !).

Vous devrez obligatoirement les changer au moindre soupçon d’intrusion, tout comme votre mot de passe.

Remarque : Pour en savoir plus sur le sel, lisez pourquoi les clés de salage sont importantes.

Empêcher que l’on découvre l’identifiant d’un auteur

Masquer les pages de profil des auteurs

En saisissant dans la barre d’adresse de votre navigateur le nom de domaine de votre site suivi de « ?author=1 », il y a des chances que vous soyez redirigé vers une page votresite.ext/author/<user>/, où <user> représente le login administrateur. Et si ça ne marche pas pour la valeur 1, ça marchera pour une autre, donc un script très élémentaire permettra à quiconque de trouver les identifiants sensibles de votre site.

Des infos qu’on aimerait cacher… Pour cela, on ignore complètement la requête et on renvoie une erreur en ajoutant ces lignes dans le fichier .htaccess situé à la racine de vote site :

# Masquage des pages d'auteur
<IfModule mod_rewrite.c>
 RewriteCond %{QUERY_STRING} ^author=([0-9]*)
 RewriteRule .* - [F]
</IfModule>

Supprimer les logins des auteurs dans les commentaires

Cette fois, c’est directement dans le code HTML des commentaires d’un article que le login de l’administrateur est dévoilé en cas de réponse de ce dernier !

Insérez donc ceci dans le fichier functions.php de vote thème enfant pour masquer les logins des auteurs :

// Suppression du login de l'auteur dans les commentaires
function remove_comment_author_class( $classes ) {
 foreach( $classes as $key => $class )
  if(strstr($class, 'comment-author-' ))
   unset( $classes[$key] );
 return $classes;
}
add_filter( 'comment_class' , 'remove_comment_author_class' );

Protéger l’accès aux dossiers et aux fichiers sensibles

Certains fichiers de votre installation WordPress contiennent des données très confidentielles qu’il faut absolument protéger.

De même, il vaut mieux empêcher l’affichage du contenu des dossiers quand ils ne contiennent pas de fichier index.php (donc par défaut accessibles au public).

Ajoutez pour cela ces lignes dans votre fichier .htaccess :

# Désactivation de l'affichage du contenu des répertoires
Options -Indexes

# Protection du fichier wp-config.php
<files wp-config.php>
 Order allow,deny
 Deny from all
</files>

# Protection des fichiers .htaccess et .htpasswds
<Files ~ "^.*\.([Hh][Tt][AaPp])">
 Order allow,deny
 Deny from all
</Files>

Supprimer les informations d’erreur de connexion

Lorsqu’on commet une erreur de saisie sur le formulaire de connexion WordPress, un message indique, selon le champs erroné, que l’identifiant n’existe pas ou que le mot de passe ne correspond pas à l’identifiant.

C’est peut-être commode pour nous, mais c’est surtout très pratique pour un pirate, qui pourrait dans un premier temps lancer une attaque permettant de trouver les logins du site, puis pour chacun de craquer leur mot de passe.

Supprimons donc ces messages à l’aide du fichier functions.php :

// Suppression des infos d'erreur de login
function remove_login_error_msg() {
 return 'Et alors, on farfouille...?';
}
add_filter( 'login_errors', 'remove_login_error_msg' );

Désactiver XML-RPC

XML-RPC est un protocole permettant de se connecter à distance à WordPress (entre autres). Des attaques de grande envergure ont exploité une vulnérabilité de sa méthode system.multicall(), qui permet d’effectuer plusieurs centaines de tentatives de connexions en un seul appel, et d’augmenter d’autant les chances de trouver un accès avant d’être bloqué.

On peut désactiver complètement XML-RPC (et supprimer une ligne d’informations dans les entêtes de page) via ces deux lignes dans le fichier functions.php :

// Désactivation XMLRPC
add_filter('xmlrpc_enabled', '__return_false');
remove_action('wp_head', 'rsd_link');

Alternativement, on peut aussi protéger le fichier xmlrpc.php situé dans le dossier racine de WordPress avec une directive Apache dans le fichier .htaccess :

# Protection du fichier xmlrpc.php
<Files xmlrpc.php>
 Order allow,deny
 Deny from all
</Files>

Remarque : Si vous utilisez JetPack, il semble que l’utilisation du module protect vous protège contre ce type d’attaque et rende ces codes inutiles (à une époque, JetPack nécessitait le protocole XML-RPC pour fonctionner, mais certains disent que ce n’est plus le cas aujourd’hui).

Masquer les numéros de version

Pourquoi faciliter la tâche des pirates en leur fournissant des informations sur le système, et donc en leur indiquant quelles failles ils pourront exploiter ?

Attention, des hackers expérimentés ou des script perfectionnés pourront toujours découvrir les versions de WordPress ou des extensions utilisées par d’autres biais, mais cela éliminera tout de même une partie des attaques. Et puisque c’est simple à mettre en œuvre, autant supprimer ou masquer ces informations inutiles au fonctionnement du site.

Les entêtes de page et le flux RSS

WordPress insère en effet dans ses entêtes de page (la balise <head>) quelques éléments inutiles pour le fonctionnement de votre site, mais exploitables par d’éventuels bots/hackers, en particulier des numéros de version, de WordPress et des fichiers CSS ou JS inclus.

Pour supprimer ces numéros de version des entêtes (et au passage du flux RSS), insérez ces quelques lignes de PHP dans le fichier functions.php de votre thème enfant :

// Suppression de la version de WordPress
remove_action('wp_head', 'wp_generator');

// Suppression version flux RSS
function remove_version_wp() {
 return '';
}
add_filter(‘the_generator’, ‘remove_version_wp’);

// Suppression des versions des fichiers css/js inclus
function remove_ver_css_js( $src ) {
 if ( strpos( $src, 'ver=' . get_bloginfo( 'version' ) ) )
  $src = remove_query_arg( 'ver', $src );
 return $src;
}
add_filter( 'style_loader_src', 'remove_ver_css_js', 9999 );
add_filter( 'script_loader_src', 'remove_ver_css_js', 9999 );

Les fichiers readme, licence, changelog…

Ces fichiers, situés à la racine de votre site ou de vos thèmes/plugins, contiennent eux aussi des informations exploitables. Les effacer manuellement n’est pas la bonne solution, puisqu’il seront recréés à chaque mise à jour de votre CMS.

Protégeons donc leur accès une fois pour toutes via une directive dans le fichier .htaccess :

# Protection des fichiers de version
<FilesMatch "^(readme.html|readme.txt|README.txt|README.md|changelog.txt|license.txt|LICENCE.txt|LICENCE)">
 Order allow,deny
 Deny from all
</FilesMatch>

Les informations de version du serveur

Sur certaines pages d’erreur renvoyées par les serveurs, on peut trouver des informations de version sur les logiciels et modules utilisés.

Voici comment indiquer à Apache de ne pas les afficher dans le fichier .htaccess :

# Masquage des informations du serveur
ServerSignature Off

Récapitulatif des codes à ajouter

Fichier function.php

/******************************************/
/*           SECURITE WORDPRESS           */
/******************************************/

// Suppression du login de l'auteur dans les commentaires
function remove_comment_author_class( $classes ) {
 foreach( $classes as $key => $class )
  if(strstr($class, 'comment-author-' ))
   unset( $classes[$key] );
 return $classes;
}
add_filter( 'comment_class' , 'remove_comment_author_class' );

// Désactivation des infos d'erreur de login
function remove_login_error_msg() {
 return 'Et alors...?';
}
add_filter( 'login_errors', 'remove_login_error_msg' );

// Désactivation XMLRPC
add_filter('xmlrpc_enabled', '__return_false');
remove_action('wp_head', 'rsd_link');

// Suppression de la version de WordPress
remove_action('wp_head', 'wp_generator');

// Suppression version dans flux RSS
function remove_version_wp() {
 return '';
}
add_filter(‘the_generator’, ‘remove_version_wp’);

// Suppression des versions des fichiers css/js inclus
function remove_ver_css_js( $src ) {
 if ( strpos( $src, 'ver=' . get_bloginfo( 'version' ) ) )
  $src = remove_query_arg( 'ver', $src );
 return $src;
}
add_filter( 'style_loader_src', 'remove_ver_css_js', 9999 );
add_filter( 'script_loader_src', 'remove_ver_css_js', 9999 );

Fichier .htaccess

Dans ce fichier, en plus des bouts de code ci-dessus, il se peut que vous deviez activer l’option FollowSymLinks, indispensable au fonctionnement du module mod_rewrite et de la personnalisation des permaliens WordPress (si ce n’est pas fait dans la configuration serveur de votre hébergement).

######################################
#         SECURITE WORDPRESS         #
######################################

# Activation du suivi des liens symboliques
Options +FollowSymLinks

# Désactivation de l'affichage du contenu des répertoires
Options -Indexes

# Masquage des informations du serveur
ServerSignature Off

# Protection du fichier wp-config.php
<files wp-config.php>
 Order allow,deny
 Deny from all
</files>

# Protection des fichiers .htaccess et .htpasswds
<Files ~ "^.*\.([Hh][Tt][AaPp])">
 Order allow,deny
 Deny from all
</Files>

# Masquage des pages d'auteur
<IfModule mod_rewrite.c>
 RewriteCond %{QUERY_STRING} ^author=([0-9]*)
 RewriteRule .* - [F]
</IfModule>

# Protection du fichier xmlrpc.php
<Files xmlrpc.php>
 Order allow,deny
 Deny from all
</Files>

# Protection des fichiers de version
<FilesMatch "^(readme.html|readme.txt|README.txt|README.md|changelog.txt|license.txt|LICENCE.txt|LICENCE)">
 Order allow,deny
 Deny from all
</FilesMatch>

Le mythe du préfixe des tables de la base de données

Changer le préfixe des tables WordPress en base de données ne protègera pas mieux votre site (une requête SQL suffit à le trouver quand on a accès à la base de données). Au contraire, c’est une procédure risquée qui peut très facilement le mettre hors-service.

Et si de nombreux éditeurs de plugins proposent encore ce service, c’est seulement pour des raisons marketing.

Remarque : Si WordPress propose de modifier ce préfixe à l’installation, c’est simplement pour permettre l’installation de plusieurs sites en utilisant la même base de données.

Conclusion

Cette liste de recommandations n’est évidemment pas exhaustive et ne garantira pas la sécurité totale de votre blog WordPress, mais elle vous mettra à l’abri d’un certain nombre de vulnérabilités.

Elle est aussi très simple à mettre en pratique et assez générique pour correspondre à tous les sites WordPress.

 

Crédit image : Background téléchargé sur Freepik