Nous allons découvrir aujourd'hui comment se protéger des attaques par flood (non distribuées) avec nginx et fail2ban. Le principe de cette attaque est relativement simple et consiste à surcharger un serveur de demandes afin de la rendre lent ou indisponible. Pour s'en protéger il faut être capable de détecter un nombre de requêtes anormalement rapproché provenant d'une même IP.
Nginx, le module ngx_http_limit_req_module
nginx possède un module (préinstallé depuis la version 0.7.21) qui permet de mettre en place une limite sur le taux de traitement des requêtes.
Pour définir une nouvelle limite on utilise la directive limit_req_zone
http {
# ...
# limit_req_zone key zone=name:size rate=rate;
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
# ...
}
- key est la clef utilisée pour limiter la fréquence, on utilise ici l'adresse ip du client.
- zone permet de donner un nom à notre limite et de définir l'espace alloué pour stocker les informations (avec 1Mo on peut sauvegarder 8000 "states" sur un système 64bits). Les "states" contiennent le nombre de requêtes dépassant la limitation par exemple.
- rate, exprimé en requêtes par seconde (r/s) ou requêtes par minute (r/m), indique la limite de traitement par rapport à la clef donnée.
Une fois nos différentes zones définies il est possible de les utiliser dans la partie server
de notre configuration à l'aide de la directive limit_req.
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
server {
# Vous pouvez l'écrire ici pour que la règle s'applique à tout votre serveur
location ~ \.php$ {
# ou seulement sur des pages à problèmes
# limit_req zone=name [burst=number] [nodelay]
limit_req zone=one burst=5;
}
Cette directive permet de définir la zone mémoire à utiliser (définie via le limit_req_zone
) ainsi que le débordement maximum autorisé (burst).
Si la fréquence des requêtes dépasse le taux défini par la zone, le traitement de ces-dernières est mis en attente afin de ne pas dépasser le taux de traitement. Les requêtes sont mises en attente jusqu'à dépasser la taille définie dans le burst
. Dans le cas d'un dépassement, la requête est terminée avec un status 503. L'option nodelay
, quant à elle, vous permet d'enlever ce processus de mise en attente des requêtes.
Les requêtes terminées par la mise en place de cette limitation seront sauvegardées dans les logs.
2016/01/12 19:11:58 [error] 6148#0: *68 limiting requests, excess: 1.102 by zone "one", client: 70.210.232.111, server: localdevserver.com, request: "GET /wp-login.php?loggedout=true HTTP/1.1", host: "localdevserver.com", referrer: "https://localdevserver.com/wp-login.php?loggedout=true"
Fail2ban, création d'une prison
Maintenant que l'on a mis en place cette limitation, on veut punir automatiquement les personnes qui essaieraient d'abuser de notre système. Nous allons pour cela créer un nouveau filtre sur fail2ban.
# /etc/fail2ban/filter.d/nginx-req-limit.conf
[Definition]
failregex = limiting requests, excess:.* by zone.*client: <HOST>
ignoreregex =
Avant de mettre en marche ce nouveau filtre vous pouvez le tester à l'aide de la commande
fail2ban-regex /var/log/nginx/error.log /etc/fail2ban/filter.d/nginx-req-limit.conf
Une fois validé, vous pouvez ajouter ce filtre dans votre configuration fail2ban local
# /etc/fail2ban/jail.local (faites une copie de jail.conf si ce fichier n'existe pas)
[nginx-req-limit]
enabled = true
filter = nginx-req-limit
action = iptables-multiport[name=ReqLimit, port="http,https", protocol=tcp]
logpath = %(nginx_error_log}s
findtime = 600
bantime = 7200
maxretry = 10
Vous pouvez affiner ces paramètres suivant vos besoins
- findtime définit l'intervalle de recherche du nombre d'occurence
- maxretry définit le nombre de correspondances à obtenir pour déclencher l'action
- bantime définit la durée du ban en secondes
Maintenant que votre filtre est enregistré vous pouvez activer votre configuration en relançant fail2ban
service fail2ban restart
Enfin, si vous voulez connaitre l'état de votre prison vous pouvez utiliser la commande
fail2ban-client status nginx-req-limit
Vous pouvez aussi analyser les logs de fail2ban
tail -f /var/log/fail2ban.log