AccueilFAQStatistiquesDiversContact

Sécurité : Linux : bloquer les attaques flood/DDoS HTTP avec ModSecurity

mod_security est un module souvent utilisé uniquement pour filtrer/rejeter des chaînes de caractères. Nous allons voir qu'il est capable de faire bien plus que cela, notamment de pouvoir bloquer des floods HTTP d'une manière plus efficace que des modules comme mod_evasive.

 cet article ne traite que des attaques HTTP, c'est à dire des requêtes multiples sur une ou plusieurs pages d'un serveur. Pour les attaques SYN flood, consultez Floodmon.

Afin de pouvoir rejeter ou blacklister les IP ayant un trop grand nombre de connexions, voici en détails 5 actions et 1 variable nécessaires pour cet usage.

  • initcol : permet d'initialiser une collection persistante. Actuellement, seulement 3 types de collections sont reconnues par ModSecurity : IP, SESSION et USER. Nous utiliserons la première afin de récupérer, enregistrer et tracer l'adresse IP du client :
  •   initcol:ip=%{REMOTE_ADDR}
    


  • setvar : permet de créer, supprimer ou mettre à jour une variable d'une collection. Afin de comptabiliser le nombre de requêtes provenant d'une même IP, nous allons créer une variable ddos pour la collection ip initialisée précédemment et l'incrémenter (+1) à chaque passage :
  •   setvar:ip.ddos=+1
    


  • deprecatevar : permet de décrémenter le compteur d'une variable en fonction de son âge. Le compteur est un nombre entier et toujours positif (si le compteur == 10 et qu'on le décrémente de 20 unités, il sera simplement réinitialisé à 0). Nous utiliserons cette action pour décrémenter le compteur de la variable ip.ddos de 100 unités toutes les 10 secondes :
  •   deprecatevar:ip.ddos=100/10
    


  • drop : coupe la connexion en cours, ce qui a pour effet de 'court-circuiter' Apache en empêchant l'envoi d'une réponse HTTP et en retournant uniquement un paquet TCP FIN/ACK. Voici un exemple de capture de 2 requêtes 'GET / HTTP/1.0' bloquées par drop et dont les FIN/ACK retournés sont indiqués par les signes x :
  • Contrairement à deny qui, lui, retourne une page d'erreur HTTP (généralement un code 403), l'avantage de drop est d'économiser les ressources système et la bande passante en ne donnant pas suite à la requête.
    Nous l'utiliserons pour les requêtes d'IP 'suspicieuses', c'est à dire ayant trop de connexions mais pas assez pour confirmer qu'il s'agit bien d'un flood, Dos ou DDos. Cela permettra d'éviter de blacklister un utilisateur un peu trop pressé/nerveux qui ouvrirait de nombreuses pages de votre site dans 10 onglets de son navigateur. Dans notre exemple, toute IP faisant plus de 25 requêtes par tranche de 10 secondes fera l'objet d'un drop et, comme nous l'avons vu avec deprecatevar, son compteur sera décrémenté de 100 unités passé ce délais, ce qui permettra à cet utilisateur de se calmer un peu :

      SecRule IP:DDOS "@gt 25" "nolog,drop"
    

     Important :
    - drop ne fonctionne pas avec les versions de mod_security pour Windows !
    - il est préférable d'utiliser nolog sinon chaque drop sera enregistré dans les logs de mod_security, ce qui pourrait provoquer un flood important des logs.

  • exec : permet d'exécuter une commande ou un script. Aucun paramètre ne peut être passé mais toutes les variables d'environnements le seront. Nous l'utiliserons pour blacklister définitivement les IP ayant plus de 50 requêtes par tranche de 10 secondes en appelant un petit client/serveur Perl qui se chargera de bloquer l'IP avec iptables. Vous trouverez ce programme et les instructions ici : faire communiquer mod_security et iptables pour bloquer les IP en temps réel.
    On log les requêtes bloquées sans risque de flooder les fichiers log puisque les IP seront immédiatement blacklistées par iptables.

      SecRule IP:DDOS "@gt 50" "log,exec:/var/www/modsec2ipt.pl"
    

     Important : ne tentez jamais d'autoriser Apache à accéder au firewall directement (sudoers, modification des privilèges etc)  : en cas de vulnérabilité d'un script de votre site, un attaquant pourrait agir directement sur iptables comme bon lui semble et simplement depuis son navigateur.

  • REQUEST_LINE : variable utilisée pour sélectionner la requête sur laquelle on doit filtrer. Elle inclut le type (GET, POST etc), la page demandée et la version du protocole. A titre d'exemple, nous filtrerons sur les requêtes 'GET' appelant uniquement la page racine '/' ou des pages *.html, *.php, *.cgi, et *.pl et utilisant le protocole HTTP, quelle que soit sa version. Cela évitera de blacklister par erreur une IP appelant une page contenant beaucoup d'images, fichiers CSS et JS :
  •   SecRule REQUEST_LINE "^GET (?:/|.+\.html|.+\.php|.+\.cgi|.+\.pl) HTTP"
    


    Règle générique :

    
      SecAction initcol:ip=%{REMOTE_ADDR},nolog
      SecRule REQUEST_LINE "^GET (?:/|.+\.html|.+\.php|.+\.cgi|.+\.pl) HTTP" \
        "nolog,setvar:ip.ddos=+1,deprecatevar:ip.ddos=100/10"
      SecRule IP:DDOS "@gt 50" "log,exec:/var/www/modsec2ipt.pl"
      SecRule IP:DDOS "@gt 25" "nolog,drop"
    
    

    N'oubliez pas bien entendu d'adapter cette règle aux besoins de votre serveur, notamment les pages appelées (REQUEST_LINE) ainsi que le nombre de requêtes tolérées.