WordPress est le CMS le plus répandu dans le monde, il équipe plus de 24% des sites internet mondiaux. Par conséquent il est bien normal qu’il soit très ciblé par les pirates informatiques : une seule faille dans WordPress donne accès à bien des sites internet sur lesquels héberger du contenu illégal, obtenir des informations, spammer etc. Voici mon guide personnel de hardening WordPress, issu de réflexions personnelles et de méthodes trouvées sur internet.

Dernière mise à jour : décembre 2016.

Précautions sur le serveur web

Voici les réglages recommandés sur le serveur web Apache pour héberger un site internet sans trop prêter le flanc aux attaques.

Être discret sur la version du serveur

Si les pirates connaissant la version exacte du serveur web et du système d’exploitation, il leur suffit d’aller chercher des exploits qui fonctionneront. Ne pas leur donner cette information est déjà un premier pas. Les réglages ServerSignature  et ServerTokens  de Apache permettent de ne pas s’étaler ni dans le footer des pages d’erreur du serveur web (404 par exemple), ni dans les headers HTTP.

Cette commande requiert l’accès ligne de commande à votre serveur, comme par exemple si vous avez un serveur dédié.

Si vous utilisez un hébergement mutualisé, la commande ServerSignature Off  peut également être ajoutée dans votre .htaccess.

Ne pas lister le contenu des fichiers

Le comportement par défaut d’apache lorsqu’il ne trouve pas de page index.html ou index.php, c’est d’afficher le contenu du dossier comme un explorateur de fichiers. Ce n’est pas bon du tout. Le module autoindex est responsable de ce désastre et le plus radical est de le supprimer.

Si ce module vous est utile, alors vous pouvez demander sa désactivation sur certains dossiers. Voici la règle à inclure dans la configuration apache (/etc/apache2/sites-available/site-internet).

Ou si vous utilisez un hébergement mutualisé, vous pouvez spécifier cette règle Options dans le fichier .htaccess.

Interdire les fichiers .htaccess

Cette mesure n’a de sens que pour les administrateurs qui ont accès aux fichiers de configuration de leur serveur (hébergement dédié par exemple), et non pas les hébergements mutualisés.

Par défaut avec apache2 sur Debian, les .htaccess sont justement interdits comme je l’ai remarqué ici. Et c’est préférable, car les fichiers .htaccess peuvent être déposés par des attaquants, qui trouvent ainsi le moyen de manipuler totalement le serveur web. D’ailleurs en dernière partie de cet article, je me méfie des .htaccess que je ne connais pas !

Ainsi pour la sécurité il est préférable de conserver le réglage AllowOverride None  sur votre VirtualHost apache.

Lorsque vous installez des extensions, prenez garde à regarder les fichiers .htaccess qu’elles proposent avec la commande find . -name '.htaccess'  pour retranscrire la configuration dans votre fichier de configuration. Le non-respect de ce conseil peut mener à des trous de sécurité notamment avec les extensions qui proposent d’uploader des fichiers comme group-document.Par exemple avec akismet :

Cloisonner l’environnement d’exécution PHP

J’ai été très surpris de la configuration d’Apache par défaut qui autorise un script php d’un site X à aller lister le contenu d’un site Y, voire même le modifier. La fonction PHP scandir(../)  fait des ravages. Voici comment cloisonner l’environnement d’exécution PHP, un point absolument vital pour ne pas qu’une faille sur un site soit pénalisante sur les autres sites.

Pour aller plus loin dans le cloisonnement, je préconise même l’exécution du moteur PHP dans un chroot grâce à php-fpm.

Désactiver les fonctions PHP dangereuses

Certaines fonction php sont tellement utilisées par les pirates, et pas tellement par les applications légitimes, qu’on peut les désactiver.

Dans le fichier php.ini  situé dans /etc/php/apache2/

Malheureusement on ne pas ajouter eval ici, car il ne s’agit pas d’une fonction mais une construction de language. Pour ce faire, il faudra utiliser suhosin.

En partie 5.2 de cet article, j’évoque d’autres fonctions potentiellement dangereuses. Il faut préalablement vérifier que vos CMS ou vos applications n’en font pas usage.

 

Interdire l’accès au serveur par son adresse IP

Votre site internet accessible à http://www.mon-site.fr ne doit en aucun cas être accessible par votre IP http://123.123.123.123. Les pirates scannent quotidiennement l’internet, et montrer un site visible sur une adresse IP sans nom de domaine ouvre la porte aux attaques aveugles pour lesquelles votre IP est la seule raison d’être attaqué.

Donc assurez-vous de répondre un code 403 : forbidden sur votre IP. Vous pouvez y arriver par exemple avec les règles suivantes dans le virtualhost par défaut d’apache /etc/apache2/sites-enabled/000-default.conf. Le préfixe 000 permet de s’assurer que ce VirtualHost sera utilisé si la requête du client web ne réfère à aucun domaine configuré sur le serveur (précédence par ordre alphabétique).

Le mot-clé _default_ peut également être emplyé pour ce VirtualHost un peu particulier.

Si votre serveur est hébergé chez OVH avec un hostname de type ns123456.ip-123-123-123.eu , je vous recommande de ne pas configurer de certificat SSL en bonne et due forme sur ce domaine, car le certifical auto-signé « snakeoil » rendra l’accès encore plus compliqué via HTTPS avec les navigateurs et les outils CLI comme cURL et wget. Après tout, c’est ce qu’on veut, non ?

Précautions pour l’accès aux fichiers

La méthode de dépôt et d’accès aux fichiers doit être sécurisée elle aussi avec un mot de passe fort et un cryptage lors du transfert des données. Personnellement j’utilise ssh et scp sur mes serveurs dédiés, avec des protections configurées dans openssh.

La plupart des hébergements mutualisés proposent ftp, il vaut mieux basculer sur ftps (ftp + SSL) lorsque c’est possible. Les serveurs ssh proposent parfois sftp (ssh + ftp) qui est un bon choix, bien que pas aussi bon que scp (le pendant « transfert de fichiers » de ssh).

Comme bons clients Windows pour ftps on a FileZilla, et pour scp on a WinSCP.

Restrictions sur MySQL

Utilisateur dédié à la base de données

Une règle qui peut paraître évidente, c’est d’utiliser un utilisateur MySQL différent pour chaque base de données gérée. Comme cela, même si un site internet est compromis, les bases de données ne risquent pas d’être touchées.

Ces ordres MySQL ci-dessous créent un utilisateur my-user qui a les droits de lecture et de modification sur la table1 de la base de données my_db, et les droits de lecture seule sur la table2. Vous pouvez les rentrer en ligne de commande ou avec une interface utilisateur comme PhpMyAdmin.

Appliqué à WordPress on peut autoriser la modification sur toutes les tables une à une, sauf la table wp_users. En effet, vous ne voulez pas qu’un pirate crée un Administrateur supplémentaire qui aura le droit de vie et de spam sur le site.

Après vérification cela donne :

Si le site internet n’a pas vocation à être modifié, l’idéal serait de basculer toutes les tables en lecture seule.

Pour certains sites à page unique, on peut même se demander s’il ne serait pas préférable d’aspirer cette page sous la forme d’un fichier html et de quelques css et js, afin de transformer le CMS vulnérable en page statique invulnérable.

Modifier les préfixes de table

Les préfixes de table sont par défaut wp_  mais dès l’installation, WordPress nous propose de les modifier. Ces préfixes permettent d’éviter qu’un attaquant ne puisse deviner trop facilement le nom des tables.

Ces préfixes ont également un aspect pratique puisqu’ils permettraient en théorie de mettre plusieurs sites internet dans une même base de données, bien que cela ne soit pas la chose la plus propre du monde.

Pour un site internet existant, on peut modifier les préfixes dans la base MySQL mais il faut modifier le paramètre table_prefix en conséquence dans le fichier wp-config.php. Également dans la base elle-même il y a des champs dans la table wp_options  qui doivent être modifiés.

Restrictions propres à WordPress

Règles de bon sens

Pour commencer, les comptes utilisateurs sur WordPress doivent être difficiles à deviner et le mot de passe doit être « fort » c’est à dire long et avec différents types de caractères : des lettres minuscules et majuscules, des chiffres et des signes de ponctuation.

Les extensions peuvent présenter des failles de sécurité donc il vaut mieux les limiter au strict minimum. Ne jamais installer de thème ou d’extension trouvée n’importe où sur le web car les virus sont courants.

Mises à jour de WordPress

WordPress est particulièrement visé par les pirates par sa forte présence sur le web, et de plus c’est lui qui est en première ligne sur votre serveur. Pour ces raisons il est absolument indispensable d’effectuer des mises à jour régulières.

Les mises à jour de sécurité sont généralement faites de manière autonomes par le CMS, et il existe des extensions pour automatiser cette tâche. On peut bien sur envisager de mettre en service un script qui va télécharger la nouvelle version de WordPress pour la décompresser à la racine du site, cette simple opération devrait normalement suffire.

Enfin, les mises à jour concernent également les extensions et les thèmes qui peuvent présenter des failles de sécurité.

Restriction des pages de login et d’administration aux utilisateurs amis

La page /wp-login.php  et le dossier /wp-admin  contiennent des formulaires de connexion. Pour limiter les risques il vaut mieux restreindre l’accès à des adresses IP « amies » ou grâce à une protection par mot de passe via le serveur web.

Dans cet exemple précis, j’ai déplacé les règles de restriction IP dans un fichier commun que je peux modifier une fois pour toutes. Voici le contenu de ip.protection.conf .

 

Une variante assez pratique est d’autoriser ces contenus aux IP amies, mais aussi aux autres IP qui réussiraient à saisir un mot de passe correct. Exemple :

Le contenu de md5.protection.conf sera :

Le contenu de htdigest sera créé grâce à la commande htdigest (et non pas htpasswd). Exemple :

Attention, on fait appel ici au module auth_digest qui doit être activé dans /etc/apache2/mods-enabled . Selon la RFC2617, le « realm » utilisé devrait être unique pour chaque utilisateur.

Pour moi, auth_digest est largement supérieur à auth_basic (ligne AuthType Basic ), car même sans l’utilisation de HTTPS, le mot de passe n’est jamais transmis en clair sur le réseau. Ainsi, je ne vois pas quel peut être l’avantage de auth_basic sur auth_digest. Ah si, j’en ai trouvé un sur Wikipédia : la fonction de hachage MD5 est interdite sur les applications qui doivent être certifiées FIPS.

Dans les deux cas, le mot de passe n’est pas stocké en clair sur le serveur (commande htdigest  pour auth_digest et htpasswd  pour auth_basic).

 

Interdictions totales sur certains fichiers

Le fichier de configuration wp-config.php est utilisé par les autres pages php du site, mais il ne doit jamais être lu par un internaute.

Les fichiers .htaccess doivent subir le même traitement afin de ne pas dévoiler sa configuration à n’importe qui. En général cela est configuré par défaut sur le serveur web, mais il est toujours bon de vérifier.

La page /xmlrpc.php  est à l’origine destinée à recevoir des commandes distantes pour manipuler le contenu du site WordPress. En pratique cette page reçoit très souvent des attaques par force brute, les attaquants cherchent à deviner le mot de passe. A mon avis cette page doit recevoir le même traitement que wp-login.php  ou même wp-config.php .

Interdiction d’exécuter du php dans le répertoire uploads

Le répertoire /wp-content/uploads contient tous les media uploadés sur le site (images, sons, vidéos) dans une arborescence souvent triée par date. J’ai souvent vu des attaques qui déposent dans ce répertoire un script php malicieux plutôt qu’un media, et elles n’ont ensuite plus qu’à l’exécuter.

En interdisant l’exécution de php dans ce dossier, on s’assure que l’attaquant ne pourra pas exécuter son code malicieux même s’il réussit à le déposer. Voici ce qu’on peut faire dans le fichier de configuration apache.

Il y a deux points bien distincts dans cette configuration : le php_flag  désactive complètement l’exécution de php dans ce répertoire, et le FilesMatch  en interdit l’accès. Si on se contente du php_flag , le fichier php reste téléchargeable comme du plain text. Si on se contente du FilesMatch , un code php dont l’extension n’est pas php pourrait être exécuté. Avec ces deux précautions c’est plutôt solide.

Interdiction d’exécuter du php sauf là où c’est interdit

Une variante de la proposition ci-dessus, c’est d’interdire l’exécution de tout script php, sauf ceux qui se nomment index.php. Cette règle n’empêchera pas les includes de fichiers php, mais refusera l’accès direct à un script au nom bizarre. Cette variante est encore plus sécuritaire, car elle n’autorise que les fichiers explicitement nommés. C’est une méthodologie que l’on retrouve communément dans les pare-feu iptables qui commencent par interdire tout trafic (POLICY) pour ensuite autoriser certains protocoles (ACCEPT).

La configuration est détaillée dans cet article, qui met l’accent sur un bug de configuration apache dans lequel il ne faut pas tomber.

Désactiver la modification des fichiers php depuis l’interface wp-admin

Dans WordPress il existe une option pour désactiver la modification des fichiers php depuis l’interface d’administration. Les utilisateurs ou les administrateurs du site ne pourront pas modifier les scripts php.

Dans wp-config.php :

Masquer la version de WordPress

Dans l’idée, il faut masquer votre version de WordPress, car c’est une information que les pirates peuvent utiliser pour choisir leurs attaques. La plupart du temps, les pirates vont sur des sites où l’on peut télécharger des exploits. Un exploit est un code informatique minimaliste qui permet d’exploiter une faille. Et bien souvent, un exploit vise une version en particulier.

Pour masquer la version de WordPress on peut utiliser un module comme Acunetix WP Security ou encore modifier les fichiers de son thème. Si on veut aller au bout des choses, masquer le numéro de version n’est pas si simple, comme cela est détaillé sur cet article de boiteaweb.fr. De là à affirmer que cette précaution est inutile, il n’y a qu’un pas… que je ne franchirai pas.

Supprimer l’utilisateur ID 1

Par défaut le premier utilisateur (administrateur) porte l’ID 1 dans la table wp_users. C’est une vérité générale pour tous les WordPress, et c’est une information qui peut être utile aux attaquants pour viser les droits d’administration en modifiant le mot de passe de l’utilisateur 1.

Dans MySQL, vous pouvez donc modifier l’ID de l’administrateur pour une autre valeur.

Extensions WordPress pour la sécurité

Il existe des extensions dont le seul but est d’améliorer la sécurité de WordPress. Les administrateurs les plus scrupuleux préféreront s’occuper de la sécurité à la main. Sinon il existe par exemple Acunetix WP Security qui semble plutôt sérieux. Le principal avantage de cette extension est de voir la TODO list des actions à réaliser.

Restreindre les droits des fichiers

Avec des constats simples, on peut retirer beaucoup de libertés qui sont trop souvent exploitées par les pirates. En effet, combien de fois dans l’année avez-vous besoin de modifier les fichier php qui constituent wordpress, en dehors des mises à jour ? Personnellement pas très souvent et c’est pourquoi j’interdis toute modification de ces fichiers, et je débloque cette mesure avant chaque mise à jour.

Les droits par défaut

La communauté WordPress conseille d’appliquer par défaut les droits suivants sur toute l’installation. Du chmod 755 sur les dossiers et 644 sur les fichiers.

De mon coté je suis beaucoup plus restrictif que cela.

Les restrictions sur les fichiers wordpress

Chacun doit élaborer un script selon ses besoins qui restreint pas à pas les droits des fichiers. Petite anecdote amusante, la restriction des droits des fichiers pour ne laisser que la lecture seule est de nature a accélérer le site internet, selon quelques tests que j’ai faits.

On définit l’utilisateur des fichiers et le groupe, et on interdit tous les autres.

Pour refuser de créer des nouveaux fichiers et dossiers à la racine du site.

Restriction lecture et exécution pour les répertoires, sachant que l’exécution pour un répertoire signifie « traverser ». Lecture seule pour tous les fichiers.

On doit ouvrir en écriture uniquement dans le dossier d’uploads.

Pour insister encore sur la non-modification des scripts php existants, j’utilise l’ordre chattr pour manipuler des attributs de fichiers disponibles sous Linux, et tout particulièrement le bit d’inamovibilité. Cela vient se superposer aux droits des fichiers standards, de sorte que même root ne peut pas modifier un fichier avec le bit d’inamovibilité qui est positionné. Cette protection est probablement une des plus efficaces de cette page.

Protection du .htaccess

Parfois on trouve des archives ou des fichiers qui auraient du être supprimés. Il vaut mieux en interdire l’accès.

Attention si vous mettez en place toutes ces restrictions par un script, il vous faudra développer le script inverse pour tout débloquer et permettre les mises à jour !

Si jamais cela ne suffisait pas

Les garde-fous pour limiter la casse SEO

Imaginez une seconde que toutes ces mesures n’aient pas suffi pour empêcher un pirate de déposer du spam sur votre site internet, est-ce que vous voulez vraiment autoriser les moteurs de recherche à lire des URL qui contiennent des mots magiques comme des noms de médicaments pour l’impuissance ? Probablement pas.

Voici ce que je vous propose dans le VirtualHost du site internet. Avec cette règle, toute URL qui contient des mots interdits est redirigée vers la page d’accueil du site internet avec un code « 301 : Moved permanently ».

Ou encore, une variante qui rend le code « 410 Gone ». Ce code d’erreur est supposé indiqué au visiteur que la page a été supprimée définitivement et qu’il faut supprimer cette URL de tout lien et de tout marque page. L’inconvénient du code 410 configuré par Apache, c’est que la page affichée est très moche.

Comme amélioration, on pourrait envisager une réécriture d’URL qui pointe vers une page php qui rende à la fois un code 410 dans le header HTTP, mais qui finisse tout de même pas rediriger l’internaute (avec javascript) vers une page plus sympathique.

La règle de redirection d’URL pour rediriger toute URL qui contient le répertoire « dossier-involontaire » :

Et dans la page inexistant.php on met par exemple :

Cela aura pour effet de répondre à l’URL non désirée en indiquant un code 410. Aucun moteur de recherche ne devrait jamais indexer cette page, et si cela ne suffisait pas la balise meta robots y veille. Si jamais un internaute se promène sur cette page interdite, le script javascript va se charger de le rediriger en 100 ms.

Ce garde-fou sur des URL manifestement involontaires est presque une technique SEO, car elle peut éviter un drame de référencement si jamais le site est massivement spammé.

Les pages qui sentent le piratage : points à surveiller

Les piratages de sites internet sont inventifs et suivent de près les mises à jours des CMS. Néanmoins les scripts malicieux comportent toujours des points communs :

  • Soit ces scripts malicieux se font passer pour ce qu’ils ne sont pas avec une indentation propre et des commentaires du style « don’t be afraid, this is normal, … »
  • Soit ces scripts malicieux sont « minifiés » c’est à dire illisibles, avec toutes les ordres sur la même ligne et même éventuellement encodé en base64.

Quoi qu’il en soit pour partir en chasse contre ces scripts malicieux, il faut particulièrement surveiller les fonctions php eval() , base64_decode() , ou encore assert() .

Exemple de recherche :

Ce fichier bizarrement nommé et dont le contenu est bizarre lui aussi est malicieux, cela ne fait aucun doute. Pour dénicher des perles de ce type, voici des exemples de commandes à utiliser.

Attention tout ce qui sort n’est pas nécessairement malicieux, disons que cela peut vous aider à vous mettre sur la piste.

A surveiller également : le contenu des fichiers .htaccess ainsi que leur emplacement. Les pirates en déposent parfois pour maîtriser la configuration de votre serveur web.

Enfin, nous l’avons déjà évoqué, tout script php dans le répertoire uploads est suspect (sauf index.php vide).

Conclusion

Les attaquants ont toujours un temps d’avance sur les attaqués, cela est ainsi. La mise en œuvre de toutes ces protections devrait vous rendre nettement moins vulnérable, mais une attaque réussie est toujours possible. Si vous avez des techniques personnelles et des améliorations à suggérer, n’hésitez pas à réagir !

Si la longueur de cet article vous a découragé, ou si vous ne pensez pas pouvoir mener ces actions à bien, nous proposons nos services d’hébergement.