Firewall
avec iptables depuis le noyau 2.4 (ipchains pour linux 2.2). iptables est dans le noyau.
3 tables par défaut:
- filter: table du firewall: filtre selon condition
- 3 chaines: input, output, forward: décide de l'endroit où on applique la règle
- input: filter les paquets à destination de la machine
- output: trafic généré par la machine
- forward: concerne les paquets qui transitent par la machine (fonction de routeur, non utilisé pour un poste de travail)
- nat: pour faire du NAT
- mangle: table de manipulation des paquets IP: on peut y faire ce qu'on veut
Firewall personnel: protéger la machine Firewall réseau: protéger le réseau (pour une machine avec 2 interfaces, un routeur)
Pour lister les tables:
iptables -L
2 politiques possibles:
- laisse tout passer, sauf ce qu'on bloque (utilisé pour le firewall personnel)
- laisse rien passer, sauf ce dont on a besoin (utilisé pour le firewall réseau, les serveurs)
DDOS: distributed denial of service: x machines attaquent une machine toutes ensemble pour que celle-ci ne puissent plus répondre → service par terre.
Nous allons principalement nous intéresser à la chaîne input de la table filter.
Interdire tout le trafic provenant de la machine X (IP:192.168.2.254)
Laisser tomber les paquets:
iptables -A INPUT -s 192.168.2.254 -j DROP
Pour refuser (en notifiant la source) les paquets:
iptables -A INPUT -s 192.168.2.254 -j REJECT
Pour accepter le trafic de cette machine:
iptables -A INPUT -s 192.168.2.254 -j ACCEPT
options de iptables:
- -A: (add) ajoute dans la chaîne
- -j: (jump) si la condition est vérifiée, fais ce qui suit
Exemples avec ping: Sur la machine 192.168.2.254, taper:
iptables -A INPUT -s 192.168.2.0/24 -j DROP
Si depuis une machine de ce réseau on fait:
ping 192.168.2.254 PING 192.168.2.254 (192.168.2.254) 56(84) bytes of data. --- 192.168.2.254 ping statistics --- 9 packets transmitted, 0 received, 100% packet loss, time 8011ms
Si on fait reject à la place:
iptables -A INPUT -s 192.168.2.0/24 -j REJECT
Si depuis une machine de ce réseau on fait:
ping 192.168.2.254 PING 192.168.2.254 (192.168.2.254) 56(84) bytes of data. From 192.168.2.254 icmp_seq=1 Destination Port Unreachable From 192.168.2.254 icmp_seq=2 Destination Port Unreachable From 192.168.2.254 icmp_seq=3 Destination Port Unreachable --- 192.168.2.254 ping statistics --- 3 packets transmitted, 0 received, +3 errors, 100% packet loss, time 1998ms
Pour vider la table filter (celle par défaut):
iptables -F
f pour flush
Pour modifier la règle numéro 1 de la chaîne INPUT de la table filter (par défaut):
iptables -R INPUT 1 -s 192.168.2.0/24 -j ACCEPT
Pour effacer la règle numéro 3 de la chaîne INPUT de la table filter (par défaut):
iptables -D INPUT 3
Interdire les connexions telnet entrantes:
iptables -A INPUT -p tcp --destination-port telnet -j DROP
Pour le protocole (-p):
- tcp
- udp
- icmp (couche 3)
Interdire ping:
iptables -A INPUT -p icmp -j DROP
Interdire tous les ping sauf depuis la machine X:
iptables -A INPUT -s 192.168.2.111 -p icmp -j ACCEPT iptables -A INPUT -s 192.168.2.0/24 -p icmp -j DROP
Lorsqu'un packet arrive, il lit dans l'ordre croissant des numéros de règles. Dès qu'il trouve une règle qui matche, il applique le -j et il cesse de parcourir la chaîne.
Donc, ici, si un paquet icmp arrive de la machine 192.168.2.111, il va d'abord lire la règle 1 et l'accepter.
Si on encode les règles dans l'autre sens, la 2e règle ne sert à rien: le paquet sera dropped avant que la règle ne soit lue.
→ !!attention à l'ordre dans lequel les règles sont encodées!!
On peut insérer une règle à l'aide du flag -I CHAIN numéro (au lieu de -A). exemple : iptables -I INPUT 3 -p icmp -j DROP
Pour voir les ports ouvert, utiliser la commande netstat:
netstat -ntl Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 0.0.0.0:800 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:32768 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:2049 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:674 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:587 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:465 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:113 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:21 0.0.0.0:* LISTEN tcp 0 0 10.0.0.12:53 0.0.0.0:* LISTEN tcp 0 0 192.168.2.42:53 0.0.0.0:* LISTEN tcp 0 0 127.0.0.1:53 0.0.0.0:* LISTEN tcp 0 0 127.0.0.1:790 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:25 0.0.0.0:* LISTEN tcp 0 0 127.0.0.1:953 0.0.0.0:* LISTEN
Par défaut, il accepte tout (policy ACCEPT): <code>iptables -F iptables -L Chain INPUT (policy ACCEPT) target prot opt source destination Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination</code> Pour changer cela en drop tout par défaut: <code>iptables -P INPUT DROP iptables -L Chain INPUT (policy DROP) target prot opt source destination Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination</code> === Etablissement d'une connexion TCP === La machine A (qui veut atteindre la machine B) envoie un packet SYN pour initialiser une connexion TCP. La machine B répond par un packet SYN-ACK. La machine A renvoie une confirmation par un paquet ACK et la connexion est établie. Pour empêcher l'initialisation de connexions: <code>iptables -A INPUT -p tcp –syn -j DROP</code> Ceci protège une station de travail d'attaques extérieures pour le trafic TCP. Pour protéger une station de travail pour tous les protocoles, il faut utiliser le module state. Ce module utilise le module conntrack, qui est une liste de toutes les connexions établies par la machine = système de suivi de connexion. Le module state va vérifier qu'une connexion a déjà été initialisée. Les connexions peuvent avoir les états suivants: * NEW * ESTABLISHED * RELATED: liée à une autre connexion (ex: retour d'un ping, FTP actif) * INVALID: paquet IP mal formé <code>iptables -A INPUT -m state –state NEW -j DROP</code> -m state = charge le module state Une configuration standard pour un firewall personnel: <code>iptables -A INPUT -m state –state NEW -j DROP iptables -A INPUT -m state –state ESTABLISHED -j ACCEPT iptables -A INPUT -m state –state RELATED -j ACCEPT iptables -A INPUT -m state –state INVALID -j DROP</code> Les 2e et 3e lignes peuvent être remplacées par une seule ainsi que les 1e et 4e par une autre: <code>iptables -A INPUT -m state –state ESTABLISHED,RELATED -j ACCEPT iptables -A INPUT -m state –state NEW,INVALID -j DROP</code> Si on veut pouvoir initialiser une connexion ssh, il faut permettre la connexion dans une règle avec un numéro inférieur: <code>iptables -I INPUT 1 -p tcp –destination-port ssh -j ACCEPT</code> S'il y a des paquets invalides, ce serait bien de les journaliser (logs) pour voir s'il y a une machine défectueuse. Pareil pour le trafic initialisant des connexions (puisque c'est un poste de travail). <code>iptables -I INPUT 1 -p tcp –destination-port 22 -j LOG</code> Il faut insérer ces règles avant qu'une règle DROP, ACCEPT ou REJECT soit lue pour un paquet IP. Les logs sont écrits dans /var/log/syslog. Pour journaliser tous les paquets NEW ou INVALID: <code>iptables -I INPUT 1 -m state –state NEW,INVALID -j LOG</code> Limitation des paquets: <code>iptables -p INPUT -p icmp -m limit –limit 4/s -j ACCEPT</code> Ici, pas plus de 4 paquets entrants ICMP (ping) ne seront acceptés par seconde (évite les ping floods). Pour éviter de surcharger le fichier de logs (pas plus de 10 fois par seconde): <code>iptables -p INPUT -p icmp -m limit –limit 4/s -m state –state NEW,INVALID -j LOG</code> ===Configuration automatique du Firewall lors du démarrage du réseau=== Pour sauver la configuration: Créer un script iptables-start: <code>iptables -F iptables -P INPUT ACCEPT iptables -A INPUT -m state –state ESTABLISHED,RELATED -j ACCEPT iptables -A INPUT -m state –state NEW,INVALID -j DROP</code> Le rendre exécutable: <code>chmod 700 iptables-start</code> Créer un script iptables-stop: <code>iptables -F</code> Le rendre exécutable: <code>chmod 700 iptables-stop</code> Les sauver là où ils seront appelés lorsqu'on monte ou démonte l'interface réseau: <code>cp iptables-start /etc/network/if-pre-up.d/ cp iptables-stop /etc/network/if-post-down.d/</code> === Installation ferme (suite)=== Suite de la semaine précédente. On va configurer le firewall de chaque serveur (10.0.0.1 à .5) pour qu'il rejette tout le trafic sauf celui adressé aux services qu'il héberge et ssh. Les diffèrentes configuration seront placées dans un scritp iptables-start dans /etc/network/if.pre-up.d/ ====Routeur et Firewall du réseau==== Sur srv1 - Routeur et Firewall du réseau. Donc en plus des règles de firewall, on doit aussi prévoir du Nat pour le routage. Les ports devant être natter (2nd partie du script) devront d'abords être ouvert sur le Firewall (1ère partie du script). Sur le firewall on ne doit, bien entendu, PAS ouvrir les ports relatifs à des services locaux (syslog, proxy-apt, …). De plus, pour des raisons évidentes de sécurité, il est décidé d'ouvrir au“monde” uniquement l'accès à des ressources sécurisée (tunnel ssl), à l'exception de www et ftp (anonymous). Il en découle que tous les mots de passe ou autre données sensibles ne transiteront jamais en clair sur le web. voir 1) pour le détails des règles <code>(pascal) echo “1. Initialisation du Firewall” iptables -F iptables -F -t nat echo “2. Configuration firewall” iptables -P INPUT DROP iptables -A INPUT -p tcp –destination-port 22 -j ACCEPT iptables -A INPUT -p tcp –destination-port 2201 -j ACCEPT iptables -A INPUT -p tcp –destination-port 2202 -j ACCEPT iptables -A INPUT -p tcp –destination-port 2203 -j ACCEPT iptables -A INPUT -p tcp –destination-port 2204 -j ACCEPT iptables -A INPUT -p tcp –destination-port 2205 -j ACCEPT iptables -A INPUT -p tcp –destination-port 80 -j ACCEPT iptables -A INPUT -p tcp –destination-port 443 -j ACCEPT iptables -A INPUT -p tcp –destination-port 20 -j ACCEPT iptables -A INPUT -p tcp –destination-port 21 -j ACCEPT iptables -A INPUT -p tcp –destination-port 989 -j ACCEPT iptables -A INPUT -p tcp –destination-port 990 -j ACCEPT iptables -A INPUT -p tcp –destination-port 25 -j ACCEPT iptables -A INPUT -p tcp –destination-port 465 -j ACCEPT iptables -A INPUT -p tcp –destination-port 993 -j ACCEPT iptables -A INPUT -p tcp –destination-port 995 -j ACCEPT iptables -A INPUT -p tcp –destination-port 53 -j ACCEPT echo “3. Mise en place du routage” iptables -t nat -A PREROUTING -i eth0 -p tcp –dport 2201 -j DNAT –to-destination 10.0.0.1:22 iptables -t nat -A PREROUTING -i eth0 -p tcp –dport 2202 -j DNAT –to-destination 10.0.0.2:22 iptables -t nat -A PREROUTING -i eth0 -p tcp –dport 2203 -j DNAT –to-destination 10.0.0.3:22 iptables -t nat -A PREROUTING -i eth0 -p tcp –dport 2204 -j DNAT –to-destination 10.0.0.4:22 iptables -t nat -A PREROUTING -i eth0 -p tcp –dport 2205 -j DNAT –to-destination 10.0.0.5:22 iptables -t nat -A PREROUTING -i eth0 -p tcp –dport 80 -j DNAT –to-destination 10.0.0.2 iptables -t nat -A PREROUTING -i eth0 -p tcp –dport 443 -j DNAT –to-destination 10.0.0.2 iptables -t nat -A PREROUTING -i eth0 -p tcp –dport 20 -j DNAT –to-destination 10.0.0.2 iptables -t nat -A PREROUTING -i eth0 -p tcp –dport 21 -j DNAT –to-destination 10.0.0.2 iptables -t nat -A PREROUTING -i eth0 -p tcp –dport 990 -j DNAT –to-destination 10.0.0.2 iptables -t nat -A PREROUTING -i eth0 -p tcp –dport 989 -j DNAT –to-destination 10.0.0.2 iptables -t nat -A PREROUTING -i eth0 -p tcp –dport 25 -j DNAT –to-destination 10.0.0.4 iptables -t nat -A PREROUTING -i eth0 -p tcp –dport 465 -j DNAT –to-destination 10.0.0.4 iptables -t nat -A PREROUTING -i eth0 -p tcp –dport 993 -j DNAT –to-destination 10.0.0.4 iptables -t nat -A PREROUTING -i eth0 -p tcp –dport 995 -j DNAT –to-destination 10.0.0.4 iptables -t nat -A PREROUTING -i eth0 -p tcp –dport 53 -j DNAT –to-destination 10.0.0.3 iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE echo “Configuration routeur OK” </code> ====autres serveurs==== Pour les 4 autres serveurs, le fichier iptables-start ressemble toujours à : <code>(pascal) iptables -F iptables -P INPUT DROP iptables -A INPUT -p tcp –destination-port ssh -j ACCEPT iptables -A INPUT -p tcp –destination-port services/ou/numéro/de/port -j ACCEPT echo “Configuration firewall OK” </code> Le –destination-port peut s'écrire en chiffres ou en lettres s'il s'agit d'un port “bien connu” (ex. 22 → ssh ) srv2 : web et ftp : ports 80 (www), 443 (https) 20 (ftp-data), 21 (ftp), 989 (ftps-data), 990 (ftps) <code>(pascal) iptables -F iptables -P INPUT DROP iptables -A INPUT -p tcp –destination-port ssh -j ACCEPT iptables -A INPUT -p tcp –destination-port www,https,ftp,ftp-data,ftps,ftps-data -j ACCEPT echo “Configuration firewall OK” </code> srv3 : dns : port 53 (domain) tcp ET udp <code>(pascal) iptables -F iptables -P INPUT DROP iptables -A INPUT -p tcp –destination-port ssh -j ACCEPT iptables -A INPUT -p tcp –destination-port domain -j ACCEPT iptables -A INPUT -p udp –destination-port domain -j ACCEPT echo “Configuration firewall OK” </code> srv4 : mail : ports 25 (smtp), 465 (smtps), 143 (imap2), 220 (imap3), 993 (imaps), 110 (pop3), 995 (pop3s) <code>(pascal) iptables -F iptables -P INPUT DROP iptables -A INPUT -p tcp –destination-port ssh -j ACCEPT iptables -A INPUT -p tcp –destination-port smtp,smtps,imap2,imap3,imaps,pop3,pop3s -j ACCEPT echo “Configuration firewall OK” </code> srv5 : syslog (port 514) et proxy-apt (le port choisi dans notre config est 9999 ) <code>(pascal) iptables -F iptables -P INPUT DROP iptables -A INPUT -p tcp –destination-port ssh -j ACCEPT iptables -A INPUT -p tcp –destination-port 9999 -j ACCEPT iptables -A INPUT -p udp –destination-port syslog -j ACCEPT echo “Configuration firewall OK” </code>