Rien de très compliqué pour ouvrir l'accès au port 80 avec les règles établies précédemment (Section 2.4.3, « Filtrage de base »). En revanche, nous pouvons y ajouter quelques règles afin d'élaborer une stratégie de protection contre les dénis de services.
Exemple 4.1. Apache: configuration du filtrage TCP en entrée
# # ###################################### # TCP entrant # Il faudra ouvrir des ports au fil de l'eau # lors de la mise en place de # services TCP (ssh, apache, ...). # ###################################### # -A TCP_IN -j TCP_INLIMITS -A TCP_IN -j STATEFUL -A TCP_IN -j TCP_SYNLIMITS -A TCP_IN -p tcp -m tcp ! --tcp-flags SYN,RST,ACK SYN -m limit --limit 10/min -j LOG --log-prefix "TCP_IN:" --log-level 6 -A TCP_IN -p tcp -m tcp ! --tcp-flags SYN,RST,ACK SYN -j DROP # Ajouter les rêgles ici lors de l'installation de services TCP si ces services # doivent être ouverts # -A TCP_IN -s adresse_ip_autorisée -p tcp -m tcp --dport 80 -j ACCEPT ❶ # on peut aussi débloquer le port 80 pour tout le monde -A TCP_IN -p tcp -m tcp --dport 80 -j ACCEPT ❷ #
Les dénis de service sont une forme d'attaque visant à mettre un service hors d'état de fonctionner. L'idée générale est de noyer le serveur sous des requêtes en provenance d'une machine ou d'un groupe de machines (on parle alors dans ce dernier cas de déni de service distribués, DDoS). Cela se traduit en général par un serveur hors-service (incapable de traiter les requètes), une machine avec un CPU à 100%, une bande passante saturée, des routeurs dépassés par les évènements, voire une combinaison de ces facteurs.
La statégie déployée ici vise uniquement à protéger le serveur HTTP. Si un flot important de paquets arrive au serveur, il est trop tard pour la bande passante. Il faudra donc, dans la mesure du possible, prévoir d'autres mécanismes en amont (upstream) afin de protéger la disponibilité de son réseau contre ces attaques et leurs variantes (le DRDoS par exemple).
Un première idée consiste à limiter (avec libipt_limit), comme dans l'extrait suivant :
Exemple 4.2. Apache : Limitation de connexions avec ipt_limit
... # ###################################### # Limitation TCP entrant # Limitation du traffic TCP entrant # Le traffic hors limite est droppé. # ###################################### ## # On limite le nombre de paquets entrant sur le port http a 100 # ce nombre sera rechargé de 10 par seconde. # -A TCP_INLIMITS -p tcp --dport 80 -m limit --limit 10/sec --limit-burst 100 -j ACCEPT ❶ -A TCP_INLIMITS -p tcp --dport 80 -j DROP ❷ -A TCP_INLIMITS -j RETURN ...
Un test simple permet de vérifier si ces règles fonctionnent.
alice@linux:~$time (while true;
❶ >do
>echo -e "GET / HTTP/1.1\nHost:192.168.17.139\nKeep-Alive:300\nConnection: keep-alive\n\n";
>done) | nc 192.168.17.139 80 > /dev/null
real 0m0.162s user 0m0.140s sys 0m0.020s ... root@ubuntu:~#/sbin/iptables-restore < /etc/network/iptables
❷ ... alice@linux:~$time (while true;
❸ >do
>echo -e "GET / HTTP/1.1\nHost:192.168.17.139\nKeep-Alive:300\nConnection: keep-alive\n\n";
>done) | nc 192.168.17.139 80 > /dev/null
real 0m10.195s user 0m0.244s sys 0m0.036s
❶ | test effectué avant l'application des règles LIMIT. La commande se termine car apache ferme la connexion keep-alive après 100 requètes. |
❷ | application des règles sur le serveur |
❸ | test effectué après l'application des règles LIMIT. Le temps nécessaire pour faire aboutir les (100) requêtes et beaucoup plus long. |
Cette politique semble donc fonctionner, mais elle a un gros inconvénient : elle produit exactement l'inverse de l'effet souhaité. En effet, ces règles limtent fortement les paquets entrants à destination du port 80. En cas de déni de service, les connexions légitimes auront encore plus de mal à aboutir.
Il faudra donc, si possible, insérer des règles permettant d'accepter du traffic en provenance d'adresses que l'on désire servir quoi qu'il arrive. Cela n'est malheureusement pas toujours poossible. Il faudra donc utiliser une stratégie plus évoluée avec par exemple libipt_recent.
Le module libipt_recent permet une gestion plus fine par adresse IP.
On pourra appliquer des restictions en paquets par seconde individuellement
à chaque adresse.
On devra d'abord précéder le chaîne TCP_IN
par un saut
vers une nouvelle chaîne dédié à la gestion des limites :
Exemple 4.3. Apache : Limitation de connexions avec ipt_recent
# *filter # # Création et remise à zéro des chaînes # :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT DROP [0:0] :DROP_ME - [0:0] :ICMP_IN - [0:0] :ICMP_OUT - [0:0] :STATEFUL - [0:0] :TCP_IN - [0:0] :TCP_INLIMITS - [0:0] ❶ ... # ###################################### # TCP entrant # Il faudra ouvrir des ports au fil de l'eau # lors de la mise en place de # services TCP (ssh, apache, ...). # ###################################### # -A TCP_IN -j TCP_INLIMITS ❷ -A TCP_IN -j STATEFUL -A TCP_IN -p tcp -m tcp ! --tcp-flags SYN,RST,ACK SYN -m limit --limit 10/min -j LOG --log-prefix "TCP_IN:" --log-level 6 -A TCP_IN -p tcp -m tcp ! --tcp-flags SYN,RST,ACK SYN -j DROP ...
❶ | Création de la chaîne et mise à zéro. |
❷ | Saut vers la chaîne de limitaion
dès l'arrivée du paquet sur |
... -A TCP_IN -p tcp --dport 80 -m recent --name HTTP_DOS --set ❶ -A TCP_IN -p tcp --dport 80 -m recent --name HTTP_DOS --update --hitcount 15 --seconds 30 -j DROP ❷ ...
Le même test que précédemment permet de s'assurer que le filtrage fonctionne.
Ce n'est pas parfait. On pourra par exemple y adjoindre des listes blanches avec
d'autres règles permettant de ne pas limiter le traffic en provenance de
certaines sources de confiance. Pour une plus grande efficacité, on devra utiliser des
mécanismes de QoS permettant de limiter le traffic sortant du serveur (voir
« Chapter 9. Queueing Disciplines for Bandwidth Management
» dans [LARTC]).