Protection d’un serveur web : d’IPtables à NFtables

Chapitre Progression:

Le premier contexte, je vous propose de passer d'IPtables à NFtables. Je vais, en plus de vous exposer le contexte réel, vous mettre les règles IPtables correspondantes, cela vous permettra de voir, pour ceux qui le souhaitent, comment passer d'un mode de gestion à l'autre.

Note : Et oui, rappelez-vous, NFtables n'est qu'une "interface" de gestion pour le pare-feu Linux, qui est NetFilter. IPtables est simplement "l'ancêtre" de NFtables.

Si vous ne connaissiez pas spécialement IPtables, sachez que vous pourrez très bien faire l'exercice sans prendre pour exemple les règles IPtables 😉

I. Description du contexte

Je dispose donc d'un serveur web hébergé chez un hébergeur dans un grand Datacenter français. Mon site reçoit plusieurs dizaines de milliers de visiteurs par jour et aussi quelques pirates qui tentent des choses pour contourner ma sécurité. J'ai donc mis en place des règles IPtables correspondant aux flux suivants :

  • Mon service web est accessible en HTTP, mais aussi en HTTPS
  • Mes sites web ont besoin, pour contacter d'autres services web, d'effectuer des requêtes en HTTPS seulement (en tant que client) (attention au DNS ;))
  • Je manage mon service web en SSH sur le port 1022
  • Mon serveur mail doit être amené à aller questionner des serveurs NTP externes à et envoyer des mails sur le port 587
  • Je souhaite également mettre en place un peu de sécurité en comptant les paquets TCP de types NULL ou XMAS, cela dénote un comportement anormal. Nous allons également les bloquer
  • Tout ce qui n'est pas explicitement autorisé sera refusé
  • Mon serveur pourra pinguer, mais ne pas être pingué

Voici mes règles IPtables, pour ceux qui connaissent, vous pourrez vous en service pour faire la comparaison au final entre le résultat IPtables et NFtables :

# On autorise la sortie et l'entrée sur le port 80
iptables -A INPUT -m tcp -p tcp --dport 80 -j ACCEPT

# On autorise la sortie du protocole HTTPS (443)
iptables -A INPUT -m tcp -p tcp --dport 443 -j ACCEPT
iptables -A OUTPUT -m tcp -p tcp --dport 443 -j ACCEPT

# On autorise la sortie et l'entrée sur le port 1022 (SSH)
iptables -t filter -A INPUT -p tcp --dport 1022 -j ACCEPT
iptables -t filter -A OUTPUT -p tcp --dport 1022 -j ACCEPT

# On autorise la sortie et l'entrée sur le port 53 (DNS)
iptables -t filter -A OUTPUT -p udp --dport 53 -j ACCEPT
iptables -t filter -A INPUT -p udp --dport 53 -j ACCEPT

# On autorise la sortie des requêtes vers le port 123 (NTP)
iptables -t filter -A OUTPUT -p udp --dport 123 -j ACCEPT

# On autorise la sortie des mails vers le port 587
iptables -t filter -A OUTPUT -p tcp --dport 587 -j ACCEPT

# Refus des TCP XMAS pour éviter les scans de ports
iptables -A INPUT -p tcp --tcp-flags ALL ALL -j DROP

# Refus des TCP NULL pour éviter les scans de ports
iptables -A INPUT -p tcp --tcp-flags ALL NONE -j DROP

# On refuse tout le reste
iptables -A OUTPUT -j DROP
iptables -A INPUT -j DROP

 II. Attention, voici le corrigé !

Nous allons maintenant passer au corrigé. J'espère que vous n'avez pas triché et que vous avez réussi à faire le plus gros de l'exercice. Pas d'inquiétude, vous pourrez retourner voir le cours en cas de besoin ! 😉

table ip filter {
chain input {
type filter hook input priority 0;
ct state established,related accept # handle 2
tcp dport http accept # handle 5
tcp dport https accept # handle 6
tcp dport 1022 accept # handle 7
tcp flags & (fin | syn | rst | psh | ack | urg) > urg counter packets 0 bytes 0 # handle 8
tcp flags & (fin | syn | rst | psh | ack | urg) < fin counter packets 0 bytes 0 # handle 9
icmp type echo-reply accept # handle 10
drop # handle 11
}

chain output {
type filter hook output priority 0;
ct state established,related accept # handle 13
tcp dport https accept # handle 14
udp dport domain accept # handle 15
udp dport ntp accept # handle 16
tcp dport 587 accept # handle 17
icmp type echo-request accept # handle 18
drop # handle 19
}
}

Je vais maintenant détailler quelque peu ma correction. Pour cela, nous nous repèrerons grâce aux numéros de règles (handle) que j'ai, rappelez-vous, fait apparaitre avec l'option "-a" de "nft".

Dans un premier temps, je créer ma table "filter" avec une chaine "input" liée au Hook du même nom, même chose pour "output".

Pour la chaine "input", je commence par spécifier mon suivi de connexion (handle 2). Toutes les connexions entrantes qui sont des connexions déjà établies ou initiées par moi-même (le serveur web, en tant que client) seront acceptées.

Aux handle 5, 6 et 7, j'ouvre les ports de mon serveur qui hébergent des applications utiles aux clients, c’est-à-dire l'HTTP (port 80), l'HTTPS (port 443) et le SSH (port 1022, normalement sur le port 22 😉 ).

Ensuite, je vais compter, puis bloquer les paquets TCP Null et XMS pour des raisons que j'ai exposées dans le cours via les règles aux handle 8 et 9.

Enfin, dans la règle handle 10, je spécifie que les paquets ICMP de type echo-reply (seule les réponses donc) seront acceptés. Je termine par refuser tout ce qui n'a pas été spécifiquement accepté dans les règles précédentes.

Pour ma chaine output, je commence également par mettre en place mon conntrack (suivi des connexions). Avec les règles 15 et 16, j'autorise les paquets UDP à sortir sur les ports 53 (DNS) et 123 (NTP)

J'espère que ce cas pratique vous a plu ! Il donne en effet l'occasion de mettre en application ce que vous avez appris dans un contexte réel et en plus permet de voir la transition des règles d'IPtables vers NFtables, dans le prochain exercice, nous passerons dans le contexte de la mise en application du NAT avec NFtables.

Partagez cet article Partager sur Twitter Partager sur Facebook Partager sur Linkedin Partager sur Google+ Envoyer par mail

    Mickael Dorigny

    Co-fondateur d'IT-Connect.fr. Auditeur en sécurité des systèmes d'information chez Amossys

      mickael has 502 posts and counting.See all posts by mickael