WordPress & sécurité : 16 recommandations

Mis à jour le 17 janvier 2025

Salut !

Voici un petit topo sur la protection d’un site WordPress. À 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, à la racine de votre installation) et functions.php (à la racine de 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, 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 !

Installer un certificat SSL

L’installation d’un certificat SSL pour votre nom de domaine permet d’authentifier votre site et de sécuriser les échanges avec les utilisateurs connectés.

Elle assure notamment l’activation du protocole HTTPS, qui assure par chiffrage la confidentialité des données transférées entre le serveur et les navigateurs.

Les hébergeurs que j’ai l’habitude de fréquenter (par exemple o2switch ou OVH) proposent des certificats SSL gratuits (Let’s Encrypt) qui sont suffisants pour une très grande majorité de sites, et simplissimes à installer et renouveler.

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é.

Renommer le 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 BEAUCOUP mieux votre site (une requête SQL suffit à le trouver quand on a accès à la base de données), mais cela pourrait permettre d’éliminer les attaques les plus basiques par injection SQL.

Si la procédure est un peu risquée pour un site déjà en ligne (et peut très facilement le mettre hors-service), elle est ultra simple lors de l’installation de WordPress.

WordPress propose de modifier ce préfixe à l’installation pour permettre l’installation de plusieurs sites en utilisant la même base de données, alors pourquoi s’en priver ?

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, on admet qu’un mot de passe devrait compter au moins 12 caractères.
  • 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, etc.

Ça faciliterait beaucoup trop le travail des pirates et des botnet et leurs attaques par force brute.

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éboguer quand ça se passe mal (et statistiquement, en attendant plusieurs mois, ça se passe souvent mal).

Pensez aussi à mettre à jour le logiciel PHP sur votre serveur, afin de profiter des dernières corrections et optimisations.

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 et de pouvoir restaurer votre site en cas d’attaque trop virulente.

À noter que les sauvegardes peuvent (ou doivent) être stockées dans plusieurs endroits (disque externe, cloud, clé…) pour réduire les risques au « presque » zéro absolu.

De nombreux plugins WordPress permettent d’automatiser les sauvegardes à intervalles réguliers et de les envoyer sur le cloud, mais les hébergeurs offrent également des outils parfois plus efficaces pour restaurer rapidement certains fichiers ou la base de données, comme jetbackup, disponible dans le cPanel chez o2switch.

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.

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

Le fichier wp-config.php de votre installation WordPress contient des informations très sensibles et confidentielles qu’il faut absolument dissimuler.

Le fichier .htaccess, quant à lui, permet d’effectuer de nombreuses actions sur votre site au niveau serveur, et est un élément clé dans la protection de votre site. C’est d’ailleurs un des fichiers que nous modifions dans cet article pour y inclure des directives de sécurité 😉

Enfin, le fichier .htpasswd, s’il est présent, contient des mots de passe utilisés pour l’accès à des dossiers éventuellement protégés par le fichier .htaccess.

Il est évidemment primordial de sécuriser l’accès à ces fichiers.

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 .htpasswd
<Files ~ "^.*\.([Hh][Tt][AaPp])">
  Order allow,deny
  Deny from all
</Files>Langage du code : HTML, XML (xml)

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

Les secret keys du fichier wp-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?+,|');Langage du code : JavaScript (javascript)

Ces clés doivent être renseignées dans le fichier wp-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>Langage du code : HTML, XML (xml)

Supprimer les identifiants 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 (et de tous les auteurs des commentaires) 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
add_filter( 'comment_class', function( $classes ) {
  foreach( $classes as $key => $class )
    if(strstr($class, 'comment-author-'))
      unset( $classes[$key] );
  return $classes;
} );Langage du code : PHP (php)

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
add_filter( 'login_errors', function() {
  return 'Et alors, on farfouille...?';
} );Langage du code : JavaScript (javascript)

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 les informations associées dans les entêtes de page) via ces quelques lignes dans le fichier functions.php :

// Désactivation XMLRPC
add_filter( 'xmlrpc_enabled', '__return_false' );
remove_action( 'wp_head', 'rsd_link' );
add_filter( 'bloginfo_url', function( $output, $property ) {
    return ( $property == 'pingback_url' ) ? null : $output;
}, 11, 2 );
add_filter( 'wp_headers', function( $headers ) {
    unset( $headers['X-Pingback'] );
	return $headers;
} );Langage du code : PHP (php)

Il est aussi possible de protéger des attaques en force brute 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>Langage du code : HTML, XML (xml)

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' );
add_filter( 'the_generator', '__return_empty_string' );

// 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 );Langage du code : PHP (php)

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|license.txt|readme.txt|README.txt|README.md|changelog.txt|license.txt|LICENCE.txt|LICENCE)">
  Order allow,deny
  Deny from all
</FilesMatch>Langage du code : HTML, XML (xml)

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 OffLangage du code : PHP (php)

Bloquer l’accès aux journaux d’erreurs PHP et de debuggae WP

Selon la configuration de votre serveur, le logiciel PHP peut journaliser les erreurs de traitement survenues sur le site dans des fichiers log. Ces fichiers peuvent contenir des informations utiles pour exploiter les failles du code de votre site. Il est donc préférable de les masquer aux attaquants.

Il en est de même pour le journal de débuggage WordPress si vous l’avez activé dans wp-config.php.

# Protection des journaux d'erreurs PHP
<Files ~ "error_log">
    Deny from all
</Files>Langage du code : HTML, XML (xml)
# Protection du journal debug.log
<Files "debug.log">
    Order Allow,Deny
    Deny from all
</Files>Langage du code : HTML, XML (xml)

Empêcher le téléchargement des fichiers SQL

Certains outils permettent de faire des sauvegardes de la base de données, stockées dans les dossiers de votre installation WordPress. Mieux vaut interdire l’accès à ses fichiers afin de préserver la confidentialité des informations sensibles de votre site.

# Protection des fichiers SQL
<Files ~ "\.(sql\.gz|sql\.zip|sql)$">
    Deny from all
</Files>Langage du code : HTML, XML (xml)

Récapitulatif des codes à ajouter

Fichier function.php

add_filter( 'comment_class' , function( $classes ) {
  foreach( $classes as $key => $class )
    if(strstr($class, 'comment-author-' ))
       unset( $classes[$key] );
  return $classes;
} );

add_filter( 'login_errors', function() {
  return 'Et alors...?';
} );

add_filter( 'xmlrpc_enabled', '__return_false' );
remove_action( 'wp_head', 'rsd_link' );
add_filter( 'bloginfo_url', function( $output, $property ) {
    return ( $property == 'pingback_url' ) ? null : $output;
}, 11, 2 );
add_filter( 'wp_headers', function( $headers ) {
    unset( $headers['X-Pingback'] );
	return $headers;
});

remove_action( 'wp_head', 'wp_generator' );
add_filter( 'the_generator', '__return_empty_string' );

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 );Langage du code : PHP (php)

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).

Options +FollowSymLinks
Options -Indexes

ServerSignature Off

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

<Files ~ "^.*\.([Hh][Tt][AaPp])">
 Order allow,deny
 Deny from all
</Files>

<IfModule mod_rewrite.c>
 RewriteCond %{QUERY_STRING} ^author=([0-9]*)
 RewriteRule .* - [F]
</IfModule>

<Files xmlrpc.php>
 Order allow,deny
 Deny from all
</Files>

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

<Files ~ "error_log">
    Deny from all
</Files>

<Files "debug.log">
    Order Allow,Deny
    Deny from all
</Files>

<Files ~ "\.(sql\.gz|sql\.zip|sql)$">
    Deny from all
</Files>Langage du code : HTML, XML (xml)

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.

10 réponses à “WordPress & sécurité : 16 recommandations”

  1. Greg

    Un bon résumé ! Très utile d'avoir autant d'infos au même endroit. Merci beaucoup.

    1. Yan

      Merci pour votre message !

  2. Steph

    Merci beaucoup pour cet article, efficace et bien présenté !

    1. Yan

      Avec plaisir !

  3. André

    Merci beaucoup. Ça m’a bien servi.

  4. Pierre-Yves

    Bonjour,J’ai appliqué votre méthode pour modifier mon fichiers function.php, cela a bien fonctionné, mais pour le fichier htaccess, cela me bloque le site et me met un message d’erreur. D’ou cela peut provenir ? Merci pour vos conseils…

    1. Yan

      Bonjour,
      Le fichier .htaccess est très sensible et à la moindre erreur de syntaxe (parfois une faute de frappe), il peut mettre votre site hors ligne.
      Envoyez-moi le fichier par email car je ne peux rien vous dire à l’aveugle 😉

      1. Pierre-Yves

        Merci de votre réponse !!!
        J’ai trouvé entretemps, il s’agit de la ligne :
        # Activation du suivi des liens symboliques
        Options +FollowSymLinks
        qui bloque mon site. Mon htaccess fonctionne désormais avec les autres commandes.
        Merci beaucoup pour vos précieuses informations !!!

  5. Estelle

    Merci beaucoup, c’était exactement ce que je cherchais !!!

Laisser un commentaire

Votre adresse IP ne sera pas collectée.
Vous pouvez renseigner votre prénom ou votre pseudo si vous êtes un humain 😉

Voir aussi

  • WordPress & RGPD : Anonymiser les commentaires

  • WordPress & RGPD : Gestion des cookies avec tarteaucitron

  • Webdesign HTML/CSS : Superposition de texte sur une image