Protéger son serveur avec le firewall Iptables

24 Août 2015 | Serveur dédié | 0 commentaires

Tout ordinateur connecté à internet est susceptible de subir des tentatives d’intrusion, c’est pourquoi quand on installe un nouvel ordinateur une des premières choses à faire est d’installer ou d’activer un firewall. Les serveurs internet n’y font pas exception, c’est pourquoi il est très important quand vous configurez votre serveur dédié de mettre en place un firewall qui va limiter les ports ouverts au strict minimum afin de limiter les risques d’intrusion.

Le noyau Linux contient de base le programme Iptables qui officie comme firewall, mais de base celui-ci est vide, il ne contient aucune règle de filtrage et n’empêche aucune tentative de connexion sur quelque port que ce soit, c’est pourquoi nous allons mettre en place des règles de filtrage via un script bash que j’ai réécrit sur la base de plusieurs sources diverses et variées.

Nous allons ouvrir 3 terminaux, chacun connecté à notre serveur via SSH. Dans le premier nous vérifierons la bonne mise en place du firewall, dans le deuxième nous lancerons le script qui renseignera le firewall, et dans le troisième nous exécuterons une petite ligne de commande qui remettra automatiquement le firewall à zéro si nous nous retrouvons bloqué (ce qui peut arriver très vite, j’en ai fait l’expérience lors de l’écriture de ce script).

Premier terminal : affichage des règles d’Iptables

Dans notre premier terminal nous allons afficher les règles actuelles du firewall avec la commande suivante :

[root@server:~]# iptables -L

Ce qui devrait vous donner un résultat semblable à ce qui suit :

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

Comme nous le voyons, aucune ligne n’apparait sous les lignes commençant par target, il n’y a donc actuellement aucune règle de filtrage. Nous reviendrons plus tard sur ce terminal.

Deuxième terminal : le script

Commençons par créer un script intitulé firewall dans le dossier /etc/init.d/ :

[root@server:~]# vim /etc/init.d/firewall

Nous y ajoutons ensuite le code suivant (vous pouvez aussi télécharger le script si vous ne voulez pas tout saisir à la main; faites un clic-droit sur le lien, sélectionnez Enregistrer la cible du lien sous…, placez le fichier sur votre serveur et renommez-le en enlevant le .txt) :

#!/bin/bash

### BEGIN INIT INFO
# Provides:          firewall
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Démarre les règles iptables
# Description:       Charge la configuration du pare-feu iptables
### END INIT INFO

# On met en variable le chemin pour atteindre le programme Iptables, ainsi que sa version pour IPv6.
IPT=/sbin/iptables
IPT6=/sbin/ip6tables


function start {
    # Fonction à exécuter au démarrage du firewall, de la manière suivante :
    # firewall start

    # Vider les règles actuelles
    $IPT -t filter -F
    $IPT6 -t filter -F
    
    # Vider les règles personnelles
    $IPT -t filter -X
    $IPT6 -t filter -X
    
    # Interdire toute connexion entrante et sortante.
    # Par défaut on interdit toute connexion, on débloquera les ports nécessaires
    # par la suite. C'est pour cette raison qu'il est important de saisir ce script
    # dans un fichier et non pas directement dans votre terminal, sinon à partir
    # de la prochaine ligne nous serons bloqués, sans accès au serveur
    $IPT -t filter -P INPUT DROP
    $IPT -t filter -P FORWARD DROP
    $IPT -t filter -P OUTPUT DROP
    $IPT6 -t filter -P INPUT DROP
    $IPT6 -t filter -P FORWARD DROP
    $IPT6 -t filter -P OUTPUT DROP
    
    # Ne pas casser les connexions établies
    $IPT -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
    $IPT -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
    $IPT6 -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
    $IPT6 -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
    
    # Autoriser loopback
    $IPT -t filter -A INPUT -i lo -j ACCEPT
    $IPT -t filter -A OUTPUT -o lo -j ACCEPT
    $IPT6 -t filter -A INPUT -i lo -j ACCEPT
    $IPT6 -t filter -A OUTPUT -o lo -j ACCEPT

    # ICMP (Ping, pour voir si votre serveur est toujours accessible)
    $IPT -t filter -A INPUT -p icmp -j ACCEPT
    $IPT -t filter -A OUTPUT -p icmp -j ACCEPT
    $IPT6 -t filter -A INPUT -p icmp -j ACCEPT
    $IPT6 -t filter -A OUTPUT -p icmp -j ACCEPT

    # RTM (Real Time Monitring), pour OVH
    $IPT -A INPUT -p udp --dport 6100:6200 -j ACCEPT
    $IPT -A OUTPUT -p udp --dport 6100:6200 -j ACCEPT
    $IPT6 -A INPUT -p udp --dport 6100:6200 -j ACCEPT
    $IPT6 -A OUTPUT -p udp --dport 6100:6200 -j ACCEPT

    # SSH
    # n'oubliez pas de changer le numéro de port si vous avez configuré SSH pour écouter sur un autre port que le 22
    $IPT -t filter -A INPUT -p tcp --dport 22 -j ACCEPT
    $IPT -t filter -A OUTPUT -p tcp --dport 22 -j ACCEPT
    
    # DNS - Nécessaire pour la gestion des noms de domaine avec Bind9 si vous voulez utiliser vos propres DNS
    $IPT -t filter -A INPUT -p tcp --dport 53 -j ACCEPT
    $IPT -t filter -A INPUT -p udp --dport 53 -j ACCEPT
    $IPT -t filter -A OUTPUT -p tcp --dport 53 -j ACCEPT
    $IPT -t filter -A OUTPUT -p udp --dport 53 -j ACCEPT

    # NTP out - Pour ajuster automatiquement l'heure sur votre serveur
    $IPT -t filter -A OUTPUT -p udp --dport 123 -j ACCEPT
    
    # HTTP + HTTPS
    #$IPT -t filter -A INPUT -p tcp --dport 80 -j ACCEPT
    #$IPT -t filter -A INPUT -p tcp --dport 443 -j ACCEPT
    #$IPT -t filter -A INPUT -p tcp --dport 8443 -j ACCEPT
    #$IPT -t filter -A OUTPUT -p tcp --dport 80 -j ACCEPT
    #$IPT -t filter -A OUTPUT -p tcp --dport 443 -j ACCEPT
    #$IPT6 -t filter -A INPUT -p tcp --dport 80 -j ACCEPT
    #$IPT6 -t filter -A INPUT -p tcp --dport 443 -j ACCEPT
    #$IPT6 -t filter -A INPUT -p tcp --dport 8443 -j ACCEPT
    #$IPT6 -t filter -A OUTPUT -p tcp --dport 80 -j ACCEPT
    #$IPT6 -t filter -A OUTPUT -p tcp --dport 443 -j ACCEPT
    
    # Mail SMTP : port 25
    #$IPT -t filter -A INPUT -p tcp --dport 25 -j ACCEPT
    #$IPT -t filter -A OUTPUT -p tcp --dport 25 -j ACCEPT
    
    # Mail POP3 : port 110
    #$IPT -t filter -A INPUT -p tcp --dport 110 -j ACCEPT
    #$IPT -t filter -A OUTPUT -p tcp --dport 110 -j ACCEPT
    
    # Mail IMAP : port 143
    #$IPT -t filter -A INPUT -p tcp --dport 143 -j ACCEPT
    #$IPT -t filter -A OUTPUT -p tcp --dport 143 -j ACCEPT

    # Mail POP3S : port 995
    #$IPT -t filter -A INPUT -p tcp --dport 995 -j ACCEPT
    #$IPT -t filter -A OUTPUT -p tcp --dport 995 -j ACCEPT
    
    # FTP
    #$IPT -t filter -A INPUT -p tcp --dport 20:21 -j ACCEPT
    #$IPT -t filter -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT # pour ne pas bloquer les accès FTP en cours
    #$IPT -t filter -A OUTPUT -p tcp --dport 20:21 -j ACCEPT
    #$IPT6 -t filter -A INPUT -p tcp --dport 20:21 -j ACCEPT
    #$IPT6 -t filter -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT # pour ne pas bloquer les accès FTP en cours
    #$IPT6 -t filter -A OUTPUT -p tcp --dport 20:21 -j ACCEPT

    # Webmin
    #$IPT -t filter -A INPUT -p tcp --dport 10000 -j ACCEPT
    #$IPT -t filter -A OUTPUT -p tcp --dport 10000 -j ACCEPT

    # Anti flood ou déni de service
    $IPT -A FORWARD -p tcp --syn -m limit --limit 1/second -j ACCEPT
    $IPT -A FORWARD -p udp -m limit --limit 1/second -j ACCEPT
    
    # Limitation des scans de ports à 1 scan par seconde
    $IPT -A FORWARD -p tcp --tcp-flags SYN,ACK,FIN,RST RST -m limit --limit 1/s -j ACCEPT
    
    # Anti relais SMTP
    $IPT -N LOG_REJECT_SMTP
    $IPT -A LOG_REJECT_SMTP -j LOG --log-prefix ' SMTP REJECT PAQUET : '
    $IPT -A LOG_REJECT_SMTP -j DROP
}


function stop {
    # Fonction à exécuter à l'arrêt du firewall, de la manière suivante :
    # firewall stop

    # on remet tout à zéro et on efface les règles en cours
    $IPT -P INPUT ACCEPT
    $IPT -P OUTPUT ACCEPT
    $IPT -t filter -F
}


case "$1" in
    start|restart)
        echo -n "Démarrage du firewall..."
        stop
        start
        echo "OK."
    ;;
    stop)
        echo -n "Arrêt du firewall..."
        stop
        echo "OK."
    ;;
    *)
        echo "Utilisation : $0 {start|stop|restart}";
        exit 1
    ;;
esac

exit 0

Une fois le script saisi et enregistré, nous lui donnons les droits en exécution avec la commande suivante :

[root@server:~]# chmod +x /etc/init.d/firewall

Comme vous pouvez le constater, j’ai commenté une bonne partie des instructions, ce qui fait qu’elles ne seront pas appliquées à Iptables. Vous pourrez les décommenter au fur et à mesure de l’installation et de l’activation des programmes qui auront besoin de ces accès.

Pour l’instant n’exécutez pas ce script, car si une petite erreur s’y est glissée vous risquez d’être déconnecté de votre serveur et de ne plus pouvoir vous y reconnecter à moins de redémarrer le serveur.

Troisième terminal : la bouée de secours en cas de blocage

C’est dans ce terminal que nous allons préparer une ligne de commande qui va arrêter automatiquement notre script et remettre à zéro Iptables après avoir pressé une touche ou au plus tard 20 secondes après son lancement, ainsi nous allons pouvoir tester sans risque notre script. Voici la ligne à préparer, n’appuyez pas encore sur Enter après l’avoir saisie !

[root@server:~]# while true; do test=""; read -t 20 -p "OK? " test ; [ -z "$test" ] && /etc/init.d/firewall stop ; done

Si vous n’avez pas suffisamment de temps pour effectuer vos tests, vous pouvez modifier le chiffre après le -t. Si après avoir effectué vos tests vous réalisez que cette commande affiche en boucle OK?, il vous suffit d’appuyer sur les touches Ctrl + C dans ce terminal pour terminer la boucle.

Testons notre firewall

Ça y est, tout est en place, nous allons pouvoir passer aux choses sérieuses ! Allez dans le 3e terminal et lancez la ligne de commande. Passez rapidement dans le 2e terminal et lancez le firewall avec la commande suivante :

[root@server:~]# service firewall start

Dirigez-vous ensuite directement dans le 1er terminal et vérifiez si vos nouvelles règles ont été enregistrées. Je vous rappelle la commande à lancer pour cela :

[root@server:~]# iptables -L

Le résultat devrait être très proche de ce qui suit :

Chain INPUT (policy DROP)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere             state RELATED,ESTABLISHED
ACCEPT     all  --  anywhere             anywhere            
ACCEPT     icmp --  anywhere             anywhere            
ACCEPT     udp  --  anywhere             anywhere             udp dpts:6100:6200
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:ssh
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:domain
ACCEPT     udp  --  anywhere             anywhere             udp dpt:domain

Chain FORWARD (policy DROP)
target     prot opt source               destination         
ACCEPT     tcp  --  anywhere             anywhere             tcpflags: FIN,SYN,RST,ACK/SYN limit: avg 1/sec burst 5
ACCEPT     udp  --  anywhere             anywhere             limit: avg 1/sec burst 5
ACCEPT     tcp  --  anywhere             anywhere             tcpflags: FIN,SYN,RST,ACK/RST limit: avg 1/sec burst 5

Chain OUTPUT (policy DROP)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere             state RELATED,ESTABLISHED
ACCEPT     all  --  anywhere             anywhere            
ACCEPT     icmp --  anywhere             anywhere            
ACCEPT     udp  --  anywhere             anywhere             udp dpts:6100:6200
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:ssh
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:domain
ACCEPT     udp  --  anywhere             anywhere             udp dpt:domain
ACCEPT     udp  --  anywhere             anywhere             udp dpt:ntp

Chain LOG_REJECT_SMTP (0 references)
target     prot opt source               destination         
LOG        all  --  anywhere             anywhere             LOG level warning prefix " SMTP REJECT PAQUET : "
DROP       all  --  anywhere             anywhere

Vous voyez que la sortie de la commande est beaucoup plus complète et que nos différentes règles ont bien été enregistrées.

Mise en place finale du firewall

Maintenant que nous avons testé notre firewall et que tout fonctionne, nous pouvons le lancer pour de bon avec la commande suivante :

 

Il faut aussi que nous l’enregistrions pour qu’il se lance automatiquement au démarrage du serveur et qu’il s’arrête automatiquement  à l’arrêt du serveur (ben oui, ici on fait les choses jusqu’au bout ;-)) :

[root@server:~]# update-rc.d firewall default

Et voilà, le tour est joué, votre serveur est maintenant quelque peu protégé ! Nous verrons dans un prochain article comment le protéger un peu plus encore avec Fail2ban.

Vous avez des questions, des remarques à propos de cet article ou du script ? Vous utilisez une autre solution ? Partagez avec nous dans les commentaires !!

0 commentaires

Soumettre un commentaire

Votre adresse e-mail ne sera pas publiée.