nginx-logoRégulièrement mes sites WordPress sont victimes de tentatives d’attaques par bruteforce sur wp-login.php. C’est d’ailleurs l’URL la plus visitée sur la plupart des sites WordPress.

Un module NGinx s’occupe avec succès de ce genre d’attaques: Nginx’s Limit Req Module.

Nous allons décrire l’utilisation de ce module ci-dessous dans le cas du wp-login.php de WordPress. Cette procédure peut très facilement s’adapter pour tout autre type de site. Elle est valable pour toute version supérieure à la version 1.3.15 (http://nginx.org/en/CHANGES)

Paramétrage Global

Dans le fichier /etc/nginx/nginx.conf dans le bloc http{..}, ajouter

limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;

one est le nom de la zone.
10m est la taille de la zone. 1MB peut contenir 16000 “states” ou IP uniques.
1r/s signifie 1 requête par seconde est autorisée. Ce nombre doit être entier, aussi si vous désirez le faire baisser vous pouvez indiquer des requêtes par minutes comme par exemple: 30r/m qui correspond à 1 requête toutes les 2 secondes.

Paramétrage par Site

Une fois cette première étape de zone définie, vous pouvez modifier le fichier de configuration du site, à l’intérieur du bloc server{..} comme dans les exemples suivants:

location = /wp-login.php {  
    limit_req   zone=one  burst=4 nodelay;
...

nodelay s’assure que lorsque le nombre de requêtes a excédé la limite et un code  HTTP 503 (Service Unavailable) est retourné.

Autres Options

Dans le cas où vous préféreriez retourner un autre code d’erreur que HTTP 503, par exemple HTTP 403 (forbidden), vous pouvez ajouter la ligne suivante dans dans le bloc http{..}du fichier /etc/nginx/nginx.conf  pour un effet global, ou dans le bloc location {..} de votre site pour un effet local:
limit_req_status 403;

Test

Logs

Vous pouvez utiliser la commande suivante dans les log. Remplacer 503 avec le code d’erreur choisi si vous utilisez limit_req_status

tail -f /var/www/example.com/*.log | egrep "login|503"

Si votre serveur a été victime d’une attaque vous obtiendrez une ligne du type:

2013/09/03 13:16:51 [error] 6719#0: *1242 limiting requests, excess: 4.788 by zone "one", client: 1.2.3.4, server: exemple.com, request: "GET /wp-login.php HTTP/1.0", host: "exemple.com"

avec 1.2.3.4 l’IP bloquée.

Simuler une Attaque

Vous pouvez utiliser apache-bench pour “attaquer” votre serveur:

ab -n 100 -c 10 example.com/wp-login.php

Protéger d’autres parties

De la même manière, vous pouvez protéger d’autres parties de votre site WordPress, comme par exemple votre page de contact.

Adresse IP en “Whitelist”

Dans l’exemple du wp-login.php vous n’aurez probablement pas besoin de whitelist puisqu’il est difficile pour une humain d’envoyer des requêtes multiples à wp-login.php. Néanmoins il est possible que dans d’autres cas une whitelist d’adresse IPs soit utiles.

Pour cela, dans le le bloc http{..} du fichier  /etc/nginx/nginx.conf, ajouter la partie map{..} comme ci-dessous:

map $remote_addr $rt_filtered_ip {  
        default $binary_remote_addr;
        1.2.3.4 "";
        4.4.4.4 "";
}

1.2.3.4 et 4.4.4.4 sont des exemples d’IPs à whitelister. Vous pouvez en ajouter autant que nécessaire avec une IP par ligne en s’assurant que la seconde colonne contienne “” pour chacune d’entre elles.

Vous pouvez ensuite utiliser la variable $rt_filtered_ip

limit_req_zone $rt_filtered_ip zone=one:10m rate=1r/s;

Cette méthode précédente ne fonctionnera pas si vous désirez whitelister un segment d’adresses IP. Dans ce cas il est nécessaire d’utiliser le module geo module de NGinx comme dans l’exemple ci-dessous.

geo $rt_filterd_ip {  
    default        $binary_remote_addr;

    127.0.0.1      "";
    192.168.1.0/24 "";
    10.1.0.0/16    "";

    ::1            "";
    2001:0db8::/32 "";

    1.2.3.4        ""
}

Comment intégrer avec CSF/LFD

voir l’article CSF LFD – Bannir les bruteforce sur des sites ou outils non standard pour ajouter une règle dans LFD pour intégrer dans le firewall.