Comment protéger son site WordPress avec CrowdSec ?

I. Présentation

Dans ce tutoriel, nous allons voir comment protéger un site WordPress avec l'outil CrowdSec afin de bannir les adresses IP malveillantes.

Grâce à CrowdSec, on va pouvoir protéger notre site WordPress contre toutes les attaques courantes, notamment les scans avec des outils de sécurité, mais aussi les attaques par brute force sur le formulaire de connexion de WordPress.

Afin de pousser un peu plus loin la configuration de l'extension CrowdSec, je vais utiliser un site WordPress derrière un reverse proxy HAProxy. Si vous n'utilisez pas de reverse proxy et que votre site Web est publié directement sur Internet (ou via un NAT), vous pouvez aussi utiliser l'extension CrowdSec (et ce sera encore plus rapide).

Le site WordPress "it-connect.tech" sera mon cobaye pour cette démonstration. Je vais manipuler le serveur Web où est déployé le site WordPress afin de mettre en place CrowdSec et le "PC de l'attaquant" présent sur le schéma ci-dessous.

Je ne vais pas détailler l'installation de mon serveur Web (LAMP - Linux Apache MariaDB PHP) ni l'installation de WordPress dans ce tutoriel. Si besoin, je vous oriente vers ces deux tutoriels existants :

II. Installation de CrowdSec sur le serveur

Sur mon serveur web sous Debian 11, je vais installer CrowdSec directement à partir des dépôts officiels.

sudo apt-get update
sudo apt-get install -y crowdsec

Le cas échéant, si le paquet n'est pas disponible (sur une version Linux plus ancienne, par exemple), vous devez utiliser cette méthode pour réaliser l'installation :

curl -s https://packagecloud.io/install/repositories/crowdsec/crowdsec/script.deb.sh | sudo bash 
sudo apt install crowdsec

Lors de l'installation, CrowdSec va analyser votre machine afin de détecter les services présents et de télécharger les collections associées. Ces composants vont permettre à CrowdSec de détecter les attaques (sans les bloquer).

On peut lister les collections avec la commande suivante :

sudo cscli collections list

On peut voir que la collection "WordPress" est automatiquement installée : CrowdSec a détecté la présence du CMS. En complément, on retrouve d'autres collections, dont "base-http-scenarios", ce qui va nous permettre d'être protégé contre les attaques Web courantes, y compris sur notre site WordPress.

Suite à l'installation, il est préférable d'effectuer une mise à jour des collections pour être certain de bénéficier des dernières versions et de tous les scénarios de détection. Voici les deux commandes à saisir :

sudo cscli hub update
sudo cscli hub upgrade

III. Mise en place du Bouncer CrowdSec dans WordPress

A. Installation et configuration de l'extension CrowdSec

À partir de l'interface d'administration de WordPress, cliquez sur le lien "Ajouter" du menu "Extensions".

Grâce à la zone de recherche, vous pouvez trouver facilement l'extension "CrowdSec". Ensuite, il suffit de cliquer sur le bouton "Installer maintenant".

Dans la foulée de l'installation, cliquez sur le bouton "Activer" pour activer l'extension. Cela n'aura pas d'impact sur votre site, car il faut lier le Bouncer CrowdSec à notre instance locale CrowdSec pour que cela fonctionne.

À ce sujet, accédez à la console de votre serveur Web et saisissez la commande ci-dessous pour générer une clé d'API pour notre Bouncer. Il faudra copier cette valeur.

sudo cscli bouncers add wordpress-bouncer

Ensuite, retournez sur WordPress et cliquez à gauche sur "CrowdSec" dans le menu afin d'accéder à la configuration de l'extension. Il va falloir renseigner plusieurs options :

  • LAPI URL : indiquez "http://localhost:8080", car CrowdSec est installé sur le même serveur que WordPress.
  • Bouncer API Key : collez la clé d'API générée précédemment
  • Bouncing level : en mode "Normal bouncing", CrowdSec va bannir ou présenter le Captcha aux clients malveillants selon la configuration, tandis qu'en mode "Flex bouncing", le blocage sera toujours effectué via un Captcha. Enfin, le mode "Bouncing disabled" permet à CrowdSec d'être transparent donc il ne bloquera plus personne, y compris les pirates. Prenons le mode "Normal bouncing" pour le moment.
  • Public website only : désactivez cette option afin de protéger la partie publique du site, mais aussi l'espace d'administration (wp-admin). Si cette option est active, CrowdSec protège seulement la partie publique du site (front office).

Validez en cliquant sur le bouton "Enregistrer les modifications".

À partir de la ligne de commande de votre serveur, exécutez la commande suivante pour lister les bouncers actifs :

cscli bouncers list

On constate que le bouncer WordPress est bien présent et valide ! Bonne nouvelle !

B. Un reverse proxy ? Configurez le module remoteip

Pour fonctionner, le bouncer WordPress va s'appuyer sur les journaux du serveur Web notamment pour identifier le client source par son adresse IP.

Dans le cas où vous utilisez un reverse proxy ou un CDN comme CloudFlare, c'est l'adresse IP du proxy qui est visible dans les journaux puisque c'est lui qui communique en direct avec le serveur Web. Cela ne joue pas en notre faveur, mais heureusement on peut ajuster la configuration d'Apache pour récupérer l'adresse IP d'origine du client.

Note : en amont, il faut configurer le reverse proxy pour qu'il ajoute le champ "X-Forwarded-For" à l'en-tête des requêtes HTTP afin de transmettre l'adresse IP du client au serveur Web.

Pour configurer Apache, il faut activer le module "remoteip" (normalement installé par défaut) :

a2enmod remoteip

Ensuite, il faut modifier le fichier de configuration d'Apache :

nano /etc/apache2/apache2.conf

Il faut modifier le format des logs et plus particulièrement la ligne qui termine par "combined". Il faut remplacer "%h" par "%a" pour spécifier dans les logs l'adresse IP du client d'origine plutôt que l'adresse IP de l'hôte qui contact le serveur Web directement.

Ce qui donne :

Enfin, on va ajouter à Apache que le champ "X-Forwarded-For" contiendra l'adresse IP du client d'origine au sein de l'en-tête HTTP. Pour cela, on utilise l'option RemoteIPHeader du module remoteip. Ajoutez la ligne suivante au fichier apache2.conf :

RemoteIPHeader X-Forwarded-For

Il ne reste plus qu'à sauvegarder le fichier et redémarrer Apache :

systemctl restart apache2

Nous verrons dans la suite de ce tutoriel l'impact de cette modification sur les logs d'Apache. La configuration de CrowdSec étant prête, nous allons pouvoir attaquer notre site WordPress.

IV. Tester le bon fonctionnement

Pour simuler une attaque contre un site Web, en l'occurrence ici un site WordPress, il y a plusieurs façons de faire. On peut utiliser Nikto, Wapiti, WPScan ou tout simplement Curl avec un user-agent suspect.

C'est d'ailleurs Curl que je vais utiliser, car ce que j'aime bien quand il s'agit de faire une démo, c'est que l'on voit en direct le code de retour HTTP : 200 quand la page se charge correctement, et il passe à 403 ou 401 une fois que CrowdSec est intervenu (le code dépend de la décision : bannir ou captcha).

On va contacter notre site en utilisant le user-agent OpenVAS (un outil de sécurité), ce qui ne devrait pas plaire à CrowdSec, car il est dans la liste des "bad user agent". Ce qui donne la commande :

curl -I https://it-connect.tech -H "User-Agent: OpenVAS"

Sur la copie d'écran ci-dessous, on peut voir qu'au début le serveur Web me répond bien, avec un code HTTP 200 donc j'accède au site. Ensuite, j'obtiens une réponse "403 Forbidden", ce qui correspond à un accès refusé. On va aller voir avec un navigateur ce qu'il se passe...

À partir du navigateur, si je tente d'accéder à l'espace d'administration de mon site WordPress ou au site en lui-même, j'obtiens un message qui m'indique je suis actuellement banni par le système ! Nous verrons dans la suite de ce tutoriel comment personnaliser cette page.

À partir de la ligne de commande, on peut lister les décisions actives dans CrowdSec et on peut voir la présence de notre adresse IP publique. L'action "BAN" montre bien que l'adresse IP est bannie pour une raison claire "http-bad-user-agent", ce qui montre clairement que CrowdSec n'a pas aimé que je me présente avec le user-agent OpenVAS.

sudo cscli decisions list

Si l'on regarde les journaux d'Apache, on peut voir la ligne avec le code HTTP 403, et cette même ligne commence bien par l'adresse IP publique utilisée par le PC de l'attaquant. Toutes les autres lignes visibles sur l'image ci-dessous correspondent aux différents "check alive" effectué par le reverse proxy pour vérifier si le serveur Web est opérationnel (d'où l'adresse IP du reverse proxy qui apparaît toutes les secondes).

J'ai l'avantage d'être à la fois l'attaquant et l'admin du site WordPress alors je vais débloquer mon adresse IP (via un autre accès sur le serveur) :

sudo cscli decisions delete --ip X.X.X.X

On va tester d'une seconde façon l'efficacité de CrowdSec : en s'attaquant au formulaire de connexion de WordPress, accessible via la page wp-login.php.

Brute force WordPress : comment va réagir CrowdSec ?
Brute force WordPress : comment va réagir CrowdSec ?

Si on liste les décisions actives, comme nous avons fait précédemment, on peut voir que cette fois-ci la raison du blocage est différente : http-fb-wordpress_bf. CrowdSec a bien détecté que j'étais en train d'effectuer un brute force sur la page de connexion !

Notre site WordPress est protégé par CrowdSec, mais pour finir je vous propose de voir quelques options supplémentaires du Bouncer WordPress.

V. Optimiser la configuration du Bouncer WordPress

A. Les options avancées du Bouncer WordPress

Dans l'interface d'administration de WordPress, à gauche sous le menu CrowdSec cliquez sur "Advanced".

Cette partie permet d'accéder à quelques options supplémentaires, dont l'option "Trust these CDN IPs (or Load Balancer, HTTP Proxy)". Cette option va permettre de préciser les adresses IP correspondantes au CDN que vous utilisez, par exemple CloudFlare, ou alors l'adresse IP de votre reverse proxy, comme dans mon cas. C'est pour cette raison que je spécifie l'adresse IP "192.168.100.1".

Ensuite, vous pouvez activer l'option "Hide CrowdSec mentions", cela va permettre d'éviter d'afficher sur la page de blocage que c'est CrowdSec qui sécurise le site. Même si CrowdSec c'est génial, ce n'est pas la peine d'afficher le nom de l'outil publiquement. 😉

Vous pouvez sauvegarder les changements.

Au sein de la section de configuration globale de CrowdSec, nous avons choisi le mode "Normal bouncing" pour bannir les adresses IP lorsque c'est utile. Si vous choisissez le mode "Flex bouncing", un captcha sera présenté. À titre d'information, voici ce que ça donne côté utilisateur via le navigateur :

B. Personnaliser la page de blocage CrowdSec

La page de blocage qui s'affiche lorsque l'on est banni ou la page du captcha sont toutes les deux en anglais. Sachez qu'il est possible de les configurer totalement via l'extension CrowdSec de WordPress. Cette fois-ci, sous le menu "CrowdSec", choisissez "Theme customization".

Vous allez pouvoir modifier le texte des deux pages, mais aussi jouer sur les couleurs, ainsi que sur le style CSS de la page ! De cette façon, la page de blocage présentée par CrowdSec pourra respecter la charte graphique de votre site.

Voici un exemple :

Ce qui donne en production :

C. Brute force WordPress : modifier le seuil de blocage

En listant les scénarios via la ligne de commande (cscli scenarios list), on peut voir que le fichier de configuration du scénario "http-bf-wordpress_bf" est situé à cet emplacement :

/etc/crowdsec/scenarios/http-bf-wordpress_bf.yaml

Pour ajuster le comportement de ce scénario, notamment le seuil de blocage, il faut modifier ce fichier. On obtient le contenu suivant :

Il y a deux paramètres ajustables :

  • capacity: 5
  • leakspeed: "10s"

Il faut interpréter cette configuration par défaut de cette façon : nous avons un sceau (bucket) d'une capacité de 5 unités au maximum (capacity: 5) et une unité de ce sceau est retirée toutes les 10 secondes (leakspeed: "10s"). À chaque fois que j’effectue une tentative en erreur sur la page de login, une unité est ajoutée dans le sceau et à la 6ème unité, le sceau déborde donc je dois être banni (ou avoir un captcha). Vous pouvez ajuster ces deux valeurs en fonction de vos besoins.

Note : à cause de la mise en cache des informations via PHP, il peut y avoir une certaine latence entre le moment où l'action se produit et le moment où la décision est appliquée.

Avec toutes ces informations, vous êtes désormais en mesure de déployer CrowdSec sur votre serveur Web afin de protéger votre site WordPress des attaques informatiques.

VI. CrowdSec : les autres épisodes

Avant de vous laisser, je tenais à vous rappeler que j'ai déjà publié deux épisodes sur l'installation et la configuration de CrowdSec correspondant à deux autres cas de figure. Voici les liens :

Je profite de cet article et de l'actualité du moment liée à la faille de sécurité critique "Log4Shell" pour vous informer que CrowdSec a publié un scénario afin de détecter et bloquer cette attaque. Grâce aux différentes instances de la communauté CrowdSec, plus de 1 100 adresses IP ont déjà été bloquées pour avoir tenté d'exploiter la vulnérabilité Log4Shell. Vous pouvez accéder à cette liste d'IP gratuitement ici.

En complément, vous pouvez accéder à une carte qui permet de voir en temps réel les adresses IP à l'origine d'attaques cherchant à exploiter cette faille de sécurité : Log4j - Carte temps réel CrowdSec.

Partagez cet article Partager sur Twitter Partager sur Facebook Partager sur Linkedin Partager sur Google+ Envoyer par mail

Florian Burnel

Ingénieur système et réseau, cofondateur d'IT-Connect et Microsoft MVP "Cloud and Datacenter Management". Je souhaite partager mon expérience et mes découvertes au travers de mes articles. Généraliste avec une attirance particulière pour les solutions Microsoft et le scripting. Bonne lecture.

florian has 3872 posts and counting.See all posts by florian

One thought on “Comment protéger son site WordPress avec CrowdSec ?

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.

 

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.