Un serveur étant tout le temps connecté à Internet il est accessible par tout le monde. C'est donc une cible de choix pour des attaquants qui peuvent y trouver des informations confidentielles ou se servir de ce dernier dans un botnet. Il est donc important de ne pas négliger la sécurité d'un serveur. Beaucoup de pages sur le web décrivent comment mettre en place un firewall pour linux, mais la majorité d'entre elles fait l'impasse sur le filtrage de l'IPv6.
Cette page décrit la mise en place d'un firewall utilisant iptables
et ip6tables
pour bloquer le trafic non souhaité en IPv4 et en IPv6. Il ne s'agit pas d'une solution parfaite mais elle apporte une sécurité non négligeable.
Ce firewall peut être catégorisé comme restrictif. En effet il va bloquer tout le trafic entrant et sortant et n'autoriser que des protocoles spécifiques :
Un port ouvert en entrée INPUT
correspond à un service hébergé sur votre machine, par exemple un service IMAP sur le port TCP 143.
Un port ouvert en sortie OUTPUT
correspond lui à un service que vous voulez contacter à l'extérieur, par exemple un serveur HTTP sur le port 80 (utile pour faire les mises à jour APT)
Il est important de noter que ces listes sont distinctes et peuvent être totalement différentes. L'erreur couramment rependue est de penser qu'il faut ouvrir un port en entrée pour accéder à un service.
Ce firewall fonctionne comme un script shell qui exécute des commandes iptables
et ip6tables
. Il sera placé dans le répertoire /etc/init.d/
qui regroupe des scripts lancés au démarrage du système. Ce script se base sur une distribution Debian Squeeze. Si le fonctionnement d'iptables est similaire sur toutes les distribution, les scripts de démarrages peuvent eux fonctionner différemment.
Le script se situera dans le fichier /etc/init.d/firewall
.
#!/bin/sh ### BEGIN INIT INFO # Provides: firewall # Required-Start: $local_fs $remote_fs # Required-Stop: $local_fs $remote_fs # Should-Start: $time $network $syslog iptables firehol shorewall ipmasq arno-iptables-firewall # Should-Stop: $network $syslog iptables firehol shorewall ipmasq arno-iptables-firewall # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Applies iptables rules # Description: Applies iptables rules to enable firewall protection on IPv4 and IPv6 ### END INIT INFO ##### START USER CONFIG # Do you want to log dropped packets in /var/log/messages ? LOG_DROPPED=1 # # List of ports to open TCP_INPUT_PORTS="22 53 25 465 143 993" TCP_OUTPUT_PORTS="53 25 465 143 993 80 443" UDP_INPUT_PORTS="53" UDP_OUTPUT_PORTS="53 123" # # List of IP to allow IPV4_ALLOWED="x.x.x.251" # ##### END USER CONFIG # Delete tables iptables -t filter -F ip6tables -t filter -F # Remove personal rules iptables -t filter -X ip6tables -t filter -X # Drop all trafic iptables -t filter -P INPUT DROP iptables -t filter -P FORWARD DROP iptables -t filter -P OUTPUT DROP ip6tables -t filter -P INPUT DROP ip6tables -t filter -P FORWARD DROP ip6tables -t filter -P OUTPUT DROP # Do not break established connections iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT iptables -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT ip6tables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT ip6tables -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT # Allow loopback iptables -t filter -A INPUT -i lo -j ACCEPT iptables -t filter -A OUTPUT -o lo -j ACCEPT ip6tables -t filter -A INPUT -i lo -j ACCEPT ip6tables -t filter -A OUTPUT -o lo -j ACCEPT # ICMPv4 iptables -t filter -A INPUT -p icmp -j ACCEPT iptables -t filter -A OUTPUT -p icmp -j ACCEPT # ICMPv6 # (drop redirect et router-solicitation packets) for type in packet-too-big destination-unreachable time-exceeded parameter-problem echo-request echo-reply router-advertisement neighbour-solicitation neighbour-advertisement do ip6tables -A INPUT -p icmpv6 --icmpv6-type $type -j ACCEPT ip6tables -A OUTPUT -p icmpv6 --icmpv6-type $type -j ACCEPT done # Allow selected IP for ip in $IPV4_ALLOWED do iptables -t filter -A INPUT --source $ip -j ACCEPT iptables -t filter -A OUTPUT --destination $ip -j ACCEPT done # Open selected ports for port in $TCP_INPUT_PORTS do iptables -t filter -A INPUT -p tcp --dport $port -j ACCEPT ip6tables -t filter -A INPUT -p tcp --dport $port -j ACCEPT done for port in $TCP_OUTPUT_PORTS do iptables -t filter -A OUTPUT -p tcp --dport $port -j ACCEPT ip6tables -t filter -A OUTPUT -p tcp --dport $port -j ACCEPT done for port in $UDP_INPUT_PORTS do iptables -t filter -A INPUT -p udp --dport $port -j ACCEPT ip6tables -t filter -A INPUT -p udp --dport $port -j ACCEPT done for port in $UDP_OUTPUT_PORTS do iptables -t filter -A OUTPUT -p udp --dport $port -j ACCEPT ip6tables -t filter -A OUTPUT -p udp --dport $port -j ACCEPT done # Logging if test $LOG_DROPPED -eq 1 then # IPv4 iptables -N LOGGING iptables -A INPUT -j LOGGING iptables -A OUTPUT -j LOGGING iptables -A LOGGING -p udp --sport 67 --dport 68 -j DROP # Do not log DHCP requests from bad admins iptables -A LOGGING -m limit --limit 4/hour --limit-burst 2 -j LOG --log-prefix "iptables dropped: " --log-level 4 iptables -A LOGGING -j DROP # IPv6 ip6tables -N LOGGING ip6tables -A INPUT -j LOGGING ip6tables -A OUTPUT -j LOGGING ip6tables -A LOGGING -p icmpv6 -j DROP # Do not log dropped icmpv6 paquets ip6tables -A LOGGING -m limit --limit 4/hour --limit-burst 2 -j LOG --log-prefix "ip6tables dropped: " --log-level 4 ip6tables -A LOGGING -j DROP fi
Après avoir créé ce fichier il faut l'adapter à vos besoin en configurant :
/var/log/messages
(0=Non et 1=Oui)
Ensuite il faut lui attribuer les bonnes permissions :
chown root:root /etc/init.d/firewall && chmod 755 /etc/init.d/firewall
Vous pouvez à présent tester ce firewall :
/etc/init.d/firewall
Si vous avez toujours accès à votre serveur c'est que tout se déroule bien.
Vous pouvez vérifier la liste des ports ouverts avec :
iptables -L -v
et ip6tables -L -v
En l'état actuel le firewall filtre bien vos connexions aussi bien en IPv4 qu'en IPv6. Cependant si vous redémarrez le serveur les règles iptables seront remises à zéro. Pour éviter cela il faut enregistrer le script en tant que script de démarrage avec la commande :
insserv firewall
Rappel : Sur d'autres systèmes que Debian et Ubuntu le système de script de démarrage peut fonctionner différemment, à vous de l'adapter à vos besoins.
Enfin si vous souhaitez le désinstaller :
insserv -r firewall
Même si iptables est configuré pour ne mettre que quatre enregistrements par heure dans le fichier de log pour une même requête, le journal peut grossir considérablement à cause de requêtes inoffensives qu'il n'est pas utile de garder. C'est le cas des broadcasts DHCP que certains serveurs font à tort. Pour éviter d'enregistrer ces requêtes une règle supplémentaire est disponible dans la partie logging du script.
Vous pouvez consulter les logs à l'aide de :
grep “iptables dropped:” /var/log/messages | tail -n 20
ou grep “ip6tables dropped:” /var/log/messages | tail -n 20