62 votes

Conseils et astuces pour iptables

Je suis sûr que les administrateurs système de Linux sont assez familiers avec iptables l'interface utilisateur de l netfilter cadre de filtrage de paquets.

Maintenant, cette "Question" est censée être une Wiki communautaire pour rassembler les différents morceaux de iptables sagesse. Rien n'est trop commun ou trop obscur. Publiez tout ce que vous savez qui pourrait aider d'autres personnes à tirer le maximum de iptables .

6voto

Zsolt Sz. Points 347

Bloquer les attaques ICMP

Ajoutez les règles suivantes, de préférence dans -t raw -A PREROUTING

-p icmp -m u32 ! --u32 "4&0x3FFF=0"   -j DROP
-p icmp -m length --length 1492:65535 -j DROP

La première règle bloque tous les paquets ICMP dont le "fragmentation flag" est différent de 0. jamais être fragmentés ; ils doivent transporter de petites charges utiles)

La deuxième règle bloque les paquets ICMP non fragmentés de taille excessive.

5voto

Sam Points 37

(à partir de mon fichier iptables_tricks.txt, recompilé à partir de beaucoup d'endroits :P)

Fait attendre iptables 15 secondes entre les nouvelles connexions provenant de la même IP sur le port 22 (SSH) :

 iptables -A INPUT -p tcp -i eth0 -m state --state NEW --dport 22 -m recent --update --seconds 15 -j DROP
 iptables -A INPUT -p tcp -i eth0 -m state --state NEW --dport 22 -m recent --set -j ACCEPT

4voto

user68579 Points 141

4voto

Mattt Points 1

En utilisant FireHOL - enveloppeur iptables pratique

Je l'ai trouvé beaucoup plus intuitif que les commandes directes d'iptables. Surtout pour les personnes ayant une expérience antérieure avec d'autres pare-feu :

FireHOL est un pare-feu iptables produisant des pare-feu iptables à état de filtrage de paquets, sur des hôtes et routeurs Linux hôtes et routeurs Linux avec un nombre quelconque d'interfaces réseau, un nombre quelconque de de routes, un nombre quelconque de services desservis, un nombre quelconque de complexité entre variations des services (y compris expressions positives et négatives).

4voto

XTL Points 189

Les ensembles IP revisités

Il existe déjà une réponse mentionnant les ensembles IP. Cependant, elle est plutôt unidimensionnelle dans la mesure où elle se concentre sur les gains de performance par rapport aux règles classiques et sur le fait que les ensembles IP atténuent le problème que l'on rencontre avec de nombreuses adresses IP individuelles qui ne peuvent pas être facilement exprimées sous forme de sous-réseau dans la notation CIDR.

Notation utilisée ci-dessous

Pour ipset Je vais utiliser la notation lue par ipset restore et écrit par ipset save .

En conséquence, pour iptables (y ip6tables ), je vais utiliser la notation telle que lue par iptables-restore et écrit par iptables-save . Cela permet de raccourcir la notation et de mettre en évidence les possibilités d'utilisation d'IPv4 uniquement (préfixe -4 ) ou IPv6 uniquement (préfixe -6 ).

Dans certains exemples, nous détournerons le flux de paquets vers une autre chaîne. La chaîne est supposée exister à ce moment-là, donc les lignes pour créer les chaînes ne sont pas produites (le nom de la table n'est pas mentionné, ni les commandes COMMIT -à la fin).

Jeux IP avancés

Les ensembles IP peuvent faire beaucoup plus que ce qui a été mentionné dans le document l'autre réponse et vous devez absolument lire la documentation sur le jeu d'IP ( ipset(8) ) ainsi que iptables-extensions(8) en plus de cette brève entrée ici.

Par exemple, je me concentrerai principalement sur trois types d'ensembles : hash:ip , hash:net y list:set mais il y en a d'autres et ils ont tous des cas d'utilisation valables.

Par exemple, vous pouvez également faire correspondre les numéros de port, et pas seulement les adresses IP .

Sauvegarde et restauration des jeux d'adresses IP comme avec iptables-save y iptables-restore

Vous pouvez créer des déclarations d'ensembles d'IP en vrac et les importer en les introduisant dans le fichier ipset restore . Si vous voulez rendre votre commande plus résistante aux entrées déjà existantes, utilisez ipset -exist restore .

Si vos règles se trouvent dans un fichier appelé default.set que vous utiliseriez :

ipset -exist restore < default.set

Un tel fichier peut contenir des entrées pour create et à add des entrées en leur sein. Mais en général, la plupart des commandes de la ligne de commande semblent avoir une version correspondante dans les fichiers. Exemple (création d'un ensemble de serveurs DNS) :

create dns4 hash:ip family inet
create dns6 hash:ip family inet6
# Google DNS servers
add dns4 8.8.8.8
add dns4 8.8.4.4
add dns6 2001:4860:4860::8888
add dns6 2001:4860:4860::8844

Ici, un ensemble est créé pour IPv4 ( dns4 ) et un pour IPv6 ( dns6 ).

Délais d'attente sur les postes IP

Les délais d'attente dans les ensembles IP peuvent être définis par défaut par ensemble et aussi par entrée. Ceci est très utile pour les scénarios où vous voulez bloquer quelqu'un temporairement (par exemple, pour le balayage de port ou la tentative de forçage brutal de votre serveur SSH).

La façon dont cela fonctionne est la suivante (par défaut lors de la création des ensembles d'IP) :

create ssh_loggedon4 hash:ip  family inet  timeout 5400
create ssh_loggedon6 hash:ip  family inet6 timeout 5400
create ssh_dynblock4 hash:ip  family inet  timeout 1800
create ssh_dynblock6 hash:ip  family inet6 timeout 1800

Nous reviendrons plus loin sur ces ensembles particuliers et sur les raisons pour lesquelles ils sont fixés de la sorte.

Si vous voulez définir votre délai d'attente pour une adresse IP particulière, vous pouvez simplement dire :

add ssh_dynblock4 1.2.3.4 timeout 7200

Pour bloquer l'IP 1.2.3.4 pendant deux heures au lieu de la demi-heure (fixée) par défaut.

Si vous deviez regarder ça avec ipset save ssh_dynblock4 après un court moment, vous verrez quelque chose du genre :

create ssh_dynblock4 hash:ip family inet hashsize 1024 maxelem 65536 timeout 1800
add ssh_dynblock4 1.2.3.4 timeout 6954

Avertissements sur les délais d'attente

  • Les délais d'attente sont une caractéristique de tout poste donné. Si le poste n'a pas été créé avec prise en charge du délai d'attente, vous recevrez une erreur (par ex. Kernel error received: Unknown error -1 ).
  • Les délais sont donnés en secondes. Utilisez les expressions arithmétiques de Bash pour passer des minutes aux secondes, par exemple. Par exemple : sudo ipset add ssh_dynblock4 1.2.3.4 timeout $((120*60))

Vérifier si une entrée existe dans un jeu d'IP donné

A l'intérieur de vos scripts, il peut être utile de voir si une entrée existe déjà. Ceci peut être réalisé avec ipset test qui renvoie un zéro si l'entrée existe et un non-zéro sinon. Ainsi, les vérifications habituelles peuvent être appliquées dans un script :

if ipset test dns4 8.8.8.8; then
  echo "Google DNS is in the set"
fi

Cependant, dans de nombreux cas, vous préférerez utiliser la fonction -exist passer à ipset afin de lui demander de ne pas se plaindre des entrées existantes.

Remplissage de jeux d'adresses IP à partir de iptables règles

C'est, à mon avis, l'une des caractéristiques les plus intéressantes des ensembles IP. Non seulement vous pouvez comparer les entrées d'un jeu d'adresses IP, mais vous pouvez également ajouter de nouvelles entrées à un jeu d'adresses IP existant.

Par exemple dans cette réponse à la question que vous vous posez :

-A INPUT -p tcp -i eth0 -m state --state NEW --dport 22 -m recent --update --seconds 15 -j DROP
-A INPUT -p tcp -i eth0 -m state --state NEW --dport 22 -m recent --set -j ACCEPT

... dans le but de limiter le nombre de tentatives de connexion à SSH (port TCP 22). Le module utilisé recent conserve la trace des dernières tentatives de connexion. Au lieu de la state je préfère le module conntrack cependant.

# Say on your input chain of the filter table you have
   -A INPUT -i eth+ -p tcp --dport ssh -j SSH
# Then inside the SSH chain you can
# 1. create an entry in the recent list on new connections
   -A SSH -m conntrack --ctstate NEW -m recent --set --name tarpit
# 2. check whether 3 connection attempts were made within 2 minutes
#    and if so add or update an entry in the ssh_dynblock4 IP set
-4 -A SSH -m conntrack --ctstate NEW -m recent --rcheck --seconds 120 --hitcount 3 --name tarpit -j SET --add-set ssh_dynblock4 src --exist
-6 -A SSH -m conntrack --ctstate NEW -m recent --rcheck --seconds 120 --hitcount 3 --name tarpit -j SET --add-set ssh_dynblock6 src --exist
# 3. last but not least reject the packets if the source IP is in our
#    IP set
-4 -A SSH -m set --match-set ssh_dynblock4 src -j REJECT
-6 -A SSH -m set --match-set ssh_dynblock6 src -j REJECT

Dans ce cas, je redirige le flux vers le fichier SSH de telle sorte que je ne doive pas me répéter avec des -p tcp --dport ssh pour chaque règle.

Je le répète :

  • -m set fait iptables conscient que nous utilisons des commutateurs de la set (qui gère les ensembles IP)
  • --match-set ssh_dynblock4 src dit à iptables pour correspondre à la source ( src ) par rapport à l'ensemble nommé ( ssh_dynblock4 )
    • cela correspond à sudo ipset test ssh_dynblock4 $IP (où $IP contient l'adresse IP source du paquet)
  • -j SET --add-set ssh_dynblock4 src --exist ajoute ou met à jour le source ( src ) du paquet dans l'ensemble IP ssh_dynblock4 . Si une entrée existe ( --exist ), il sera simplement mis à jour.
    • cela correspond à sudo ipset -exist add ssh_dynblock4 $IP (où $IP contient l'adresse IP source du paquet)

Si vous vouliez faire correspondre l'adresse de la cible/destination à la place, vous utiliseriez dst au lieu de src . Consultez le manuel pour plus d'options.

Ensembles d'ensembles

Les ensembles IP peuvent contenir d'autres ensembles. Si vous avez suivi l'article jusqu'ici, vous vous êtes sans doute demandé s'il était possible de combiner des ensembles. Et bien sûr, c'est possible. Pour les ensembles IP ci-dessus, nous pouvons créer deux ensembles conjoints ssh_dynblock y ssh_loggedon respectivement pour contenir les ensembles IPv4-only et IPv6-only :

create ssh_loggedon4 hash:ip  family inet  timeout 5400
create ssh_loggedon6 hash:ip  family inet6 timeout 5400
create ssh_dynblock4 hash:ip  family inet  timeout 1800
create ssh_dynblock6 hash:ip  family inet6 timeout 1800
# Sets of sets
create ssh_loggedon  list:set
create ssh_dynblock  list:set
# Populate the sets of sets
add ssh_loggedon ssh_loggedon4
add ssh_loggedon ssh_loggedon6
add ssh_dynblock ssh_dynblock4
add ssh_dynblock ssh_dynblock6

Et la prochaine question qui devrait surgir dans votre esprit est de savoir si cela nous permet de match et de manipuler les ensembles IP de manière agnostique par rapport à la version IP.

Et la réponse à cette question est sans appel : OUI ! (hélas, cela n'était pas documenté explicitement la dernière fois que j'ai vérifié)

Par conséquent, les règles de la section précédente peuvent être réécrites comme suit :

-A INPUT -i eth+ -p tcp --dport ssh -j SSH
-A SSH -m conntrack --ctstate NEW -m recent --set --name tarpit
-A SSH -m conntrack --ctstate NEW -m recent --rcheck --seconds 120 --hitcount 3 --name tarpit -j SET --add-set ssh_dynblock src --exist
-A SSH -m set --match-set ssh_dynblock src -j REJECT

ce qui est beaucoup plus concis. Et oui, cette méthode est éprouvée et fonctionne à merveille.

Tout mettre en place : Défense SSH par force brute

Sur mes serveurs, j'ai un script exécuté comme une cron qui prend un tas de noms d'hôtes et les résout en adresses IP, puis les introduit dans le jeu d'IP pour les "hôtes de confiance". L'idée est que les hôtes de confiance reçoivent plus de tentatives de connexion au serveur et ne sont pas nécessairement bloqués aussi longtemps que les autres.

À l'inverse, j'ai bloqué la connexion de pays entiers à mon serveur SSH, à l'exception (potentielle) des hôtes de confiance (c'est-à-dire que l'ordre des règles compte).

Cependant, cela reste un exercice pour le lecteur. Ici, j'aimerais ajouter une solution soignée qui utilisera les ensembles contenus dans l'application ssh_loggedon défini pour permettre aux tentatives de connexion ultérieures d'être transmises et de ne pas être soumises au même examen que les autres paquets.

Il est important de se rappeler que les délais par défaut de 90 minutes pour les services de l ssh_loggedon et 30 minutes pour ssh_dynblock en regardant les éléments suivants iptables règles :

-A INPUT -i eth+ -p tcp --dport ssh -j SSH
-A SSH -m set --match-set ssh_loggedon src -j ACCEPT
-A SSH -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A SSH -m conntrack --ctstate NEW -m recent --set --name tarpit
-A SSH -m conntrack --ctstate NEW -m recent --rcheck --seconds 120 --hitcount 3 --name tarpit -j SET --add-set ssh_dynblock src --exist
-A SSH -m set --match-set ssh_dynblock src -j REJECT

A présent, vous devez vous demander comment l'adresse IP de connexion se retrouve dans le fichier ssh_loggedon sous-ensembles. Lisez donc ce qui suit...

Bonus : ajout de l'IP avec laquelle vous vous connectez lors de la connexion SSH

Si vous avez expérimenté sshrc et amis, vous aurez appris ses défauts. Mais PAM vient à la rescousse. Un module nommé pam_exec.so nous permet d'invoquer un script pendant la connexion SSH à un moment où nous savons que l'utilisateur est admis.

Sur /etc/pam.d/sshd sous le pam_env y pam_selinux ajoutez la ligne suivante :

session    optional     pam_exec.so stdout /path/to/your/script

et assurez-vous que votre version du script ( /path/to/your/script ci-dessus) existe et est exécutable.

PAM utilise des variables d'environnement pour communiquer ce qui se passe, vous pouvez donc utiliser un simple script comme celui-ci :

#!/bin/bash
# When called via pam_exec.so ...
SETNAME=ssh_loggedon
if [[ "$PAM_TYPE" == "open_session" ]] && [[ -n "$PAM_RHOST" ]]; then
    [[ "x$PAM_RHOST" != "x${PAM_RHOST//:/}" ]] && SETNAME="${SETNAME}6" || SETNAME="${SETNAME}4"
    ipset -exist add $SETNAME "$PAM_RHOST"
fi

Malheureusement, le ipset ne semble pas avoir l'intelligence intégrée de netfilter. Nous devons donc faire la distinction entre les ensembles IPv4 et IPv6 lorsque nous ajoutons notre entrée. Sinon, ipset nous supposerons que nous voulons ajouter un autre set à l'ensemble des ensembles, au lieu de l'IP. Et bien sûr, il est peu probable qu'il y ait un ensemble portant le nom d'un IP :)

Nous vérifions donc : dans l'adresse IP et ajoutez 6 au nom de l'ensemble dans ce cas et 4 autrement.

La fin.

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X