Limiter l'accès à un site / service pour un certain nombre de requêtes par IP

Il m'est arrivé de devoir limiter l'accès aux webservices de Gisgraphy en raison d'utilisateurs peu scrupuleux qui récupérent les données directement via le webservice. J'ai utilisé pour cela un module Apache appelé mod_evasive.

il s'installe très facilement sur une distribution Ubuntu avec un apt (apt-get install libapache2-mod-evasive).

une fois installer il faut le configurer en ouvrant apache2.conf. voici un exemple de configuration type :

<IfModule mod_evasive20.c>
DOSHashTableSize 3097
DOSPageCount 10
DOSSiteCount 1000
DOSPageInterval 10
DOSSiteInterval 86400
DOSBlockingPeriod 30
DOSEmailNotify "admin@domaine.fr"
DOSLogDir "/var/log/mod_evasive/"
DOSSystemCommand "/sbin/iptables -I INPUT -s %s -j DROP"
DOSWhiteList 127.0.0.1
</IfModule>

DOSSiteCount / DOSSiteInterval: Le nombre maximal de requêtes qu'une adresse IP peut faire sur le site pendant l'intervalle de temps DOSSiteInterval (en secondes).

DOSPageCount / DOSPageInterval : Le nombre maximal de requêtes qu'une adresse IP peut faire sur la même URL pendant une unité de temps DOSPageInterval (en secondes). Notez que l'URL ne contient pas les paramètres : http://monHost/monurl?param=1 est la même page que http://monHost/monurl?param=2, ce qui correspond bien à mon besoin qui est de limiter l'accès à un webservice REST

DOSBlockingPeriod :Durée pendant laquelle une adresses IP en liste noire sera refusée. un ip refusée se verra retourner une erreur 403. Par défaut, cette durée est de 10 secondes. Il peut ere utile de personnaliser la page 403 pour expliquer la raison du 'Forbidden'

DOSEmailNotify : Adresse email à laquelle envoyer une notification lorsqu'une adresse IP est ajoutée en liste noire.

DOSSystemCommand : Commande appelé lorsqu'une ip est bloquée. On peut, par exemple, utiliser iptable et rejeter tout les requêtes provenant de cette IP. l'utilisateur n'aura alors plus d'erreur 403 mais ce verra refusé l'accès au niveau socket

DOSWhiteList : Spécifie une ou plusieurs adresse IP à ne jamais positionner en liste noire.

Vous pouvez télécharger les sources à cette adresse , elles contienent un scripts de test en perl. pour comprendre le procédé, j'ai fait quelque modifications au scripts :

#!/usr/bin/perl

# test.pl: small script to test mod_dosevasive's effectiveness

use IO::Socket;
use strict;

for(0..20) {
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
print "a seconde= ",$sec ;

  my($response);
  my($SOCKET) = new IO::Socket::INET( Proto   => "tcp",
                                      PeerAddr=> "127.0.0.1");
  if (! defined $SOCKET) { die $!; }

  print $SOCKET "GET /index.html?param=$_ HTTP/1.0

";
  $response = <$SOCKET>;
  print " essai no: $_ : $response";
  close($SOCKET);
}

En l'executant avec la configuration ci dessous, mais sans DOSSystemCommand (un peu drastique), j'obtiens :


a seconde= 0 essai no: 0 : HTTP/1.1 200 OK
a seconde= 0 essai no: 1 : HTTP/1.1 200 OK
a seconde= 0 essai no: 2 : HTTP/1.1 200 OK
a seconde= 0 essai no: 3 : HTTP/1.1 200 OK
a seconde= 0 essai no: 4 : HTTP/1.1 200 OK
a seconde= 0 essai no: 5 : HTTP/1.1 200 OK
a seconde= 0 essai no: 6 : HTTP/1.1 200 OK
a seconde= 0 essai no: 7 : HTTP/1.1 200 OK
a seconde= 0 essai no: 8 : HTTP/1.1 200 OK
a seconde= 0 essai no: 9 : HTTP/1.1 200 OK
a seconde= 0 essai no: 10 : HTTP/1.1 200 OK
a seconde= 0 essai no: 11 : HTTP/1.1 200 OK
a seconde= 0 essai no: 12 : HTTP/1.1 200 OK
a seconde= 0 essai no: 13 : HTTP/1.1 200 OK
a seconde= 0 essai no: 14 : HTTP/1.1 200 OK
a seconde= 0 essai no: 15 : HTTP/1.1 200 OK
a seconde= 0 essai no: 16 : HTTP/1.1 200 OK
a seconde= 0 essai no: 17 : HTTP/1.1 200 OK
a seconde= 0 essai no: 18 : HTTP/1.1 200 OK
a seconde= 0 essai no: 19 : HTTP/1.1 200 OK
a seconde= 0 essai no: 20 : HTTP/1.1 403 Forbidden

Comme vous pouvez le voir, au bout de 20 requêtes, je suis bloqué et reçoit une erreur 403, (je ne sais pas trop pourquoi mais je suis toujours bloqué à DOSPageCount * 2, mais ca semble etre le bon comportement. Si quelqu'un à la réponse...).

Si je refais une demande 20 secondes plus tard, je suis toujours bloqué, il faut attendre 30 secondes (DOSBlockingPeriod) pour pouvoir revoir la page.

Quelques infos utiles :

mod_evasive ne peux être défini vhost par vhost

Il peux poser des problèmes pour les bots qui se voient refuser l'accès au site à partir d'un certain nombre de requêtes. Il faut ajouter leurs IP à DOSWhiteList

j'ai remarqué lors de mes tests que la période de blocage était le maximum entre DOSBlockingPeriod et DOSPageInterval, si je depasse le DOSPageCount.

Exemple : Si je mets DOSBlockingPeriod = 5 , je serais bloqué 10 secondes (la valeur de DOSPageInterval). Pareil pour DOSSiteInterval : je serai bloqué 1 journée (86400 secondes) à partir de la dernière requête bloquée si je dépasse le DOSSiteCount, et non pas 5 secondes (DOSBlockingPeriod). vous serez bloqué pendant un laps de temps correspondant à la plus grande valeur entre DOSBlockingPeriod et DOSSiteInterval

La fenêtre de blocage est une fenêtre glissante (heureusement :) )

Si je refais une requête en étant bloqué, mon temps de blocage repart à zéro.

Pour terminer, j'ai limité (au moins pour cette exemple) l'accès au site à 1000 requêtes par jour (DOSSiteCount / DOSSiteInterval), ce qui évite les petit vicieux de mettre un délai entre leur requêtes ;) Attention toutefois à ne pas mettre un DOSSiteCount trop bas car une page avec une image et une css équivaut à trois requêtes.

La discussion continue ailleurs

URL de rétrolien : https://davidmasclet.gisgraphy.com/index.php?trackback/35

Fil des commentaires de ce billet