4.4. Filtrage

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.

4.4.1. Filtrage

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 ❷
#

Régle autorisant l'accès au port 80/tcp (http) pour l'adresse adresse_ip_autorisée (qui peut aussi être un subnet). Cette règle peut être répétée autant de fois que nécessaire.

Régle autorisant l'accès au port 80/tcp (http) pour tout le monde.


4.4.2. « Protection » contre les dénis de service (DoS)

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).

4.4.2.1. Utilisation de LIMIT

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
...

cette règle autorise un 'pool' de 100 paquets entrants. Ce pool sera rechargé au rhytme de 10 par seconde

ce qui dépasse ces limites (et donc qui n'a pas pu être pris par -j ACCEPT) sera jetté.


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.

4.4.2.2. Utilisation de 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 TCP_IN.

...
-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 ❷
...

cette règle met dans la liste HTTP_DOS l'adresse IP source des paquets arrivant sur le port 80

si une IP source a été vue plus de 15 fois dans les 30 dernières secondes, il est jeté.


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]).