Diminuer une attaque DoS avec Netfilter sur Linux
Source: bortzmeyer.org
Une des plaies de l’Internet est la quantité d’attaques par déni de service (DoS pour denial of service) que l’administrateur réseaux doit gérer. Tout service connecté à l’Internet se voit régulièrement attaqué pour des raisons financières (extorsion), politiques (je critique la politique du gouvernement d’Israël, les sionistes DoSent mon site), ou simplement parce qu’un type veut s’amuser ou frimer devant ses copains. Il n’existe actuellement pas de recettes magiques pour faire face à ces attaques, je voudrais juste ici présenter et discuter les méthodes disponibles avec Netfilter, le pare-feu de Linux.
Évidemment, je ne prétends pas faire un guide général de toutes les mesures anti-DoS en un article de blog. Il existe des tas de DoS différentes, et l’administrateur réseaux doit, à chaque fois, analyser la situation et produire une réponse appropriée. Non, mon but est bien plus limité, expliquer les différentes façons de limiter le trafic entrant avec Netfilter, et discuter leurs avantages et inconvénients.
Car un des charmes (?) de Netfilter (au fait, il est parfois nommé par le nom de sa commande principale, iptables) est qu’il existe des tas de modules pour assurer telle ou telle fonction, et que ces modules se recouvrent partiellement, fournissant certaines fonctions mais pas d’autres. Et, s’il existe un zillion d’articles et de HOWTO sur la configuration d’iptables pour limiter une DoS, la plupart ne décrivent qu’un seul de ces modules, laissant l’ingénieur perplexe : pourquoi celui-ci et pas un autre ?
Commençons par le commencement. Vous êtes responsables d’un site Web, une DoS est en cours, des tas de paquets arrivent vers le port 80, faisant souffrir le serveur HTTP, qui n’arrive plus à répondre. Vous ne pouvez pas intervenir sur le trafic en amont, avant même qu’il ne passe par votre liaison Internet, cela nécessite la coopération du FAI (pas toujours évidente à obtenir, surtout si on ne s’est pas renseigné à l’avance sur les démarches à suivre). Vous pouvez parfois intervenir sur le serveur lui-même, Apache, par exemple, a tout un tas de modules dédiés à ce genre de problèmes. Mais, ici, je vais me concentrer sur ce qu’on peut faire sur Linux, ce qui fournira des méthodes qui marchent quel que soit le serveur utilisé.
D’abord, deux avertissements importants, un général et un spécifique. Le général est que les DoS sont souvent courtes et que la meilleure stratégie est parfois de faire le gros dos et d’attendre. Des contre-mesures mal conçues ou irréfléchies ont de bonnes chances d’aggraver le problème au lieu de le résoudre. Ne vous précipitez donc pas.
Et l’autre avertissement concerne le risque de se DoSer soi-même, avec certaines contre-mesures, lorsque la contre-mesure nécessite d’allouer un état, c’est-à-dire de se souvenir de quelque chose. Par exemple, si vous voulez limiter le trafic par adresse IP, vous devez avoir quelque part une table indexée par les adresses, table où chaque entrée contient le trafic récent de cette adresse. Si l’attaquant peut mobiliser beaucoup d’adresses différentes (en IPv6, c’est trivial mais, même en IPv4, c’est possible, surtout s’il n’a pas besoin de recevoir les paquets de réponse et peut donc utiliser des adresses usurpées), il peut faire grossir cette table à volonté, jusqu’à avaler toute la mémoire. Ainsi, vos propres contre-mesures lui permettront de faire une DoS encore plus facilement…
Il n’est évidemment pas possible de faire de la limitation de trafic (rate-limiting) sans état mais il faut chercher à le minimiser.
Commençons par le module le plus simple, l’un des plus connus et, je crois, un des premiers, connlimit. connlimit utilise le système de suivi de connexions (connection tracking) de Linux. Ce système permet au noyau de garder trace de toutes les connexions en cours. Il sert à bien des choses, par exemple au NAT ou au filtrage avec état. S’appuyant dessus, connlimit permet de dire, par exemple « vingt connexions HTTP en cours, au maximum » :
% iptables -A INPUT -p tcp --dport 80 -m connlimit \ --connlimit-above 20 -j DROP