Création d'une plateforme anti-ddos modulaire

Q'est-ce qu'un DDoS ? Que faire en cas de DDoS ? Comment se protéger ? Ce sont là des questions récurrentes ces temps-ci sur internet. Je vais exposer dans le présent article une solution pour se prémunir un minimum avec une architecture modulaire. L'exemple se focalisera sur les services HTTP.

Avant-propos

Un DDoS, pour faire simple, se rapporte à une attaque de type déni de service distribué. En gros, l'attaquant cherche à rendre votre service (site web, serveur mail, platefome complète...) indisponible grâce à plusieurs outils déployés sur PC zombies lancés à vos dépends en parallèle. Plus il y a d'armes (PC zombies), plus l'attaque prend de l'ampleur. De base, pour déjouer ces attaques, c'est un peu le jeu de qui a la plus grosse. Reste qu'on peut se prémunir de pas mal de chose, sans passer pour autant par des solutions (trop) honéreuses de type Arbor Networks.

Plateforme Arbor Networks Clean Pipes 2.0

On n'est pas tous milliardaires (ou du moins, pas encore). On ne peut pas tous investir dans ces solutions ni payer le tuyaux nécessaire pour jouer à qui a la plus grosse. Mais on doit se protéger. L'idée principale de cet article, réside donc dans la différence entre les notions de DoS et de DDoS, à savoir, le distributed. On cherche donc à se rapprocher autant que possible d'un DoS en segmentant l'attaque puis on travaille sur ces réductions en fonction du protocole.

Dans la suite, nous discutons de flux HTTP. Donc on filtre au niveau réseau avec du firewall puis on analyse la partie HTTP avec un WAF et on réduit les connexions au serveur client (le backend) avec une plateforme de Caching. Chaque fonction est isolée sur une brique indépendante des autres qu'on peut remplacer ou supprimer en fonction de l'usage qu'on veut avoir.

Je resterais assez succint sur la mise en place de certaines fonctionnalités avancées, sur l'évolutivité ou encore sur la centralisation des informations, ayant livré un produit un peu plus complet il y a peu.

Plateforme anti-DDoS modulaire

L'architecture est dans le Cloud : pourquoi ? parce que la virtualisation offre la souplesse nécessaire à ce type d'architecture et qu'on pourra voir dans de potentielles évolutions, à définir des règles au niveau DNS pour isoler des régions géographiques sur tel ou tel fournisseur sans impacter les autres datacenter virtuel.

Spécificités de la plateforme

La plateforme est découpée en "colonne". Toutes les colonnes sont équivalentes à la base. On essaie d'isoler une colonne par opérateur. A l'intérieur de chaque colonne, on aura une "ligne" de fonction composée d'autant de serveur de chaque type appelé "brique". Dans le cas de l'article, une colonne HTTP contient trois lignes d'un seul serveur à chaque fois :

  • firewall
  • WAF (Web Application Firewall)
  • Caching

J'ai rédigé cet article et les scripts liés de manière spécifique au serveur OVH. Des adaptations sont à prévoir pour d'autres mais dans l'absolu, tout devrait être fonctionnel tel quel. Chaque brique est en soit une machine virtuelle (dans le cas présent, une Debian Squeeze) avec des ressources affectées en fonction de vos besoins et moyens. Ici, 2 core et 8 Go de Ram à chaque fois. On y copie importe l'arborescence de deploiement qui va bien, on lance le script, et rouler jeunesse.

Au niveau réseau, on sépare la partie management de la partie service.

Le serveur VMware ESXi 5.0 n'a de base qu'une IP de management. On restreint ces services de management aux seules IP qui s'y connecteront : votre bureau.

Ensuite, vient le cas des différentes VIP qu'on demande à OVH :

  • 3 pour les services publiques (dont la première servira aussi pour le VPN
  • 1 pour le honeypot
  • 1 pour la communication du caching avec le backend

Entre eux, chaque niveau communique sur un VLAN spécifique.

Enfin, chaque serveur a une patte de management sur un réseau privé, utilisable exclusivement via le serveur de VPN.

Le comportement est simple : lorsqu'un client se veut se connecter à la plateforme protégée, il le fait via une requête HTTP sur un fqdn précis. Ce fqdn est un alias vers un catch-all DNS de notre service de protection. Ce catch-all correspond à un gros Round Robin DNS vers les différentes VIP. C'est le point qui génère la segmentation. Plus de VIP seront disponible, plus la segmentation sera importante. L'attaquant visera soir le fqdn et donc toutes les VIP, se qui va répartir ses PC zombies, soit les différentes VIP, mais lui même devra avoir assez de PC zombies sous la main.

Le firewall entame alors son petit travail : analyser les paquets. Ici on reste basique avec un lot de règles iptables. On pourrait y greffer à la limite un IPS pour compléter la brique. Les règles sont de deux types :

  • basique : pré enregistrées au démarrage du service
  • dynamique : générée par les outils de bannissement

Les règles basiques correspondent à des règles de "bonne usage" contre les DoS classiques. Les règles dynamiques sont produites soit à la main, soit par l'ensemble du service : détection des scans de port, fail2ban, ... Peu importe quelle brique détecte une IP à bannir, celle-ci le sera au niveau du firewall. De plus, le bannissement se fait via un TARPIT pour la partie TCP et un DROP pour le reste.

Les scripts qui suivront sont issues de la première version du PoC. Certains points sont à faire évoluer mais la base est présente.

Le firewall

Au début je pensais utiliser une BSD avec du pf. Mais je me suis ravisé : pf ne permet pas la partie TARPIT qui est tout de même bien sympathique. Qu'est-ce que TARPIT ? C'est un redimensionnement de la fenêtre TCP à 0. Ou de manière plus imagée, c'est le pendant d'un SYN Flood côté défense. On ne renvoie pas l'ACK à un client mais on tue sa requête. Le résultat est d'engorger progressivement sa pile TCP. Le tout proportionnellement à l'ampleur de l'attaque.

Le firewall portent donc trois VIP de service. Chaque voit son port 80 poussé vers le WAF. La première voit en plus un port poussé vers le VPN. Ici, le 3006/tcp.

A côté de cela, pour garder une certaine dynamique dans les règles iptables, on ne bloque pas tout. Juste quelques attaques de type DoS standard. Le reste, on fera du préventif ou cas par cas.

Du coup, portsentry est utilisé pour détecter les scans de ports et déclencher le bamnissement.

On y installe aussi un honeypot qui simule un serveur Windows bien ouvert sur la 4e VIP. Toute tentative de connexion dessus sera détectée dans les logs par un fail2ban qui déclenchera le bannissement.

Enfin, quelques paramétrages fins sont à faire spécifiquement sur le firewall :

# Tuning automatique de la fenêtre TCP
net.ipv4.tcp_moderate_rcvbuf=1
# Communication entre les différents noeuds pour notifier d'un engorgement (RFC 3168)
net.ipv4.tcp_ecn=0
# Désactive le discover automatique du MTU
net.ipv4.ip_no_pmtu_disc=0
# On désactive le démarrage lent d'une nouvelle connexion qui a déjà ouvert une session HTTP
net.ipv4.tcp_slow_start_after_idle=0
# On bloque les requêtes de type ICMP echo en broadcast
net.ipv4.icmp_echo_ignore_broadcasts=1
# On préfère traiter toutes les requêtes TCP afin de peupler les règles iptables
net.ipv4.tcp_abort_on_overflow = 1
# C'est l'arme contre les SYN FLOOD : une connexion n'est gardée en mémoire que si le serveur a reçu l'ACK
net.ipv4.tcp_syncookies = 1
# On ne laisse pas retenter un paquet TCP
net.ipv4.tcp_orphan_retries = 0
# Simple réduction de taille du paquet TCP en y mettant pas le champ time - moins de charge CPU
net.ipv4.tcp_timestamps = 0
# Active les acknoledge selectif : on ne répond pas à tous - pour de la perf, pour pourrait le mettre à 0
net.ipv4.tcp_sack = 1
# Tuning de la fenêtre TCP - on est restrictif
net.ipv4.tcp_window_scaling = 1

D'autres paramètres plus globaux sont initialisés également.

Le WAF

Le WAF est donc le firewall applicatif. En gros, c'est une brique HTTP permettant d'analyser les requêtes et générer un comportement sécuritaire spécifique. On peut utiliser du mod_security (qui existe aussi pour nginx maintenant) ou du naxsi. La grosse différence, le premier fonctionne à coup de blacklist statiques, le second fonctionne à coup de whitelist et de blacklist générée lors d'un mode d'apprentissage.

Lorsqu'un client HTTP est connecté et a un comportement suspicieux, on aura la joie d'avoir une ligne dans les logs correspondants. En interfaçant avec fail2ban et le script qui va bien, on pourra déclarer l'IP de ce client au firewall qui la bannira.

N'oubliez pas de déclarer les VIP sur la loopback.

Le caching

J'ai déjà eu l'occasion de rédiger différents articles sur le caching (création et comparaison). Ici le but est juste de mettre une brique rapidement en place pour démontrer le fonctionnement.

On reprend donc un nginx configuré pour le caching. La spécificité de cette brique est qu'elle sort directement sur internet via son IP publique (donc sans repasser par le firewall, contrairement aux autres briques).

Au niveau sécurité de la patte publique, on bloque tout à coup de TARPIT/DROP par défaut sur celle-ci.

Conclusion

L'ensemble des scripts est disponible sur mon github. La commande magique deploy se charge d'installer et configurer les différents points pour un rôle donné.

La commande de management ddos permet déjà quelques outils. Elle est à lancer avec un compte nommé sysadmin à qui on réduira les possibilité via sudo. Le compte root est bloqué pour le SSH.

N'oubliez pas que ceci est un PoC et doit donc servir de base. Il est utilisable quasiment tel quel mais il serait mieux d'avoir un niveau suffisant pour l'adapter et l'améliorer.

Imaginez une centralisation des informations, un back office, une mutualisation des firewall pour différents protocoles, des tunnels GRE entre vous et les plateformes cibles, un TARPIT directement intégré au SMTP (cf BSD), ...

Dans tous les cas, voici une idée du résultat au niveau filtrage :

Graphique statistique sur le filtrage anti DDoS

Vus : 133
Publié par Francois Aichelbaum : 171