[Section précédente : Tables] [Index] [Section suivante : Traduction des Adresses IP ("NAT")]
Les règles de filtrage énumèrent les critères auxquels doivent se conformer les paquets et spécifient les actions qui y sont associées : bloquer ou laisser passer. Ces règles sont évaluées de façon séquentielle de la première à la dernière (du haut vers le bas dans les fichiers de règles utilisés). Sauf utilisation du mot-clef quick dans l'une d'entre elles, chaque paquet est évalué à l'aide de toutes les règles avant qu'une décision finale ne soit prise. L'action (block ou pass) associée à la dernière règle dont les critères se rapportent au paquet traité est appliquée. La première règle est un tout laisser passer implicite de sorte que si aucune règle n'est applicable à un paquet, celui-ci est accepté (pass).
action [direction] [log] [quick] [on interface] [af] [proto protocol] \
[from src_addr [port src_port]] [to dst_addr [port dst_port]] \
[flags tcp_flags] [state]
Cette politique de blocage par défaut repose sur deux règles :
block in all
block out all
Cela suffit à interdire tout trafic dans un sens comme dans l'autre et ce sur toutes les interfaces de la machine.
Quelques exemples:
# Autoriser le trafic entrant sur l'interface dc0
# en provenance du réseau local 192.168.0.0/24,
# à destination de la machine dont l'adresse IP est 192.168.0.1.
# Dans le même temps, autoriser le trafic sortant par l'interface dc0.
pass in on dc0 from 192.168.0.0/24 to 192.168.0.1
pass out on dc0 from 192.168.0.1 to 192.168.0.0/24
# Autoriser le trafic TCP entrant sur l'interface fxp0
# à destination d'un serveur HTTP.
# Le nom de l'interface - fxp0 - est utilisé comme adresse de destination
# pour les paquets autorisés. pass in on fxp0 proto tcp from any to fxp0 port www
Mauvais :
block in on fxp0 proto tcp from any to any port ssh
pass in all
La ligne block n'aura aucun effet. Les paquets seront bien évalués suivant ses critères, mais la ligne suivante annulera tout effet de cette première règle.
Mieux :
block in quick on fxp0 proto tcp from any to any port ssh
pass in all
A première vue c'est la même chose. Si la ligne block correspond, l'option quick provoque l'arrêt des tests pour chaque paquet qui correspond aux critères de la première règle. Les paquets qui n'y satisfont pas seront quant à eux testés au regard des critères de la règle suivante.
Conserver l'état des connexions a pour avantage de simplifier les règles de filtrage et d'améliorer les performances. PF évalue les paquets quel que soit leur sens : il n'est alors plus nécessaire d'écrire les règles pour les paquets des flux retour. PF consacre ainsi beaucoup moins de temps à inspecter les paquets.
Quand une règle crée un état, le premier paquet qui déclenche l'activation de celle-ci provoque la création d'un enregistrement dans la table d'état des connexions en cours. Par la suite, non seulement les paquets allant de l'expéditeur au destinataire sont rattachés à cette table et donc autorisés à passer, mais également les paquets qui appartiennent aux réponses du destinataire.
A partir d'OpenBSD 4.1, toutes les règles de filtrage créent automatiquement une entrée dans la table d'état dès qu'un paquet les active. Dans les versions précédentes d'OpenBSD, une règle de filtrage doit explicitement utiliser l'option keep state.
Voici un exemple pour OpenBSD 4.1 et les versions suivantes :
pass out on fxp0 proto tcp from any to any
Voici un exemple pour OpenBSD 4.0 et les versions antérieures :
pass out on fxp0 proto tcp from any to any keep state
Ces règles autorisent les connexions TCP sortantes sur l'interface fxp0 mais aussi les paquets retour. L'option keep state permet donc d'augmenter les performances du pare-feu car la recherche dans la table d'état est beaucoup plus rapide que l'opération consistant à évaluer un paquet au regard de toutes les règles de filtrage.
L'option modulate state fonctionne de la même façon que l'option keep state à ceci près qu'elle ne s'applique qu'aux paquets TCP sortants. L'option modulate state renforce le caractère aléatoire de leurs numéros de séquence initiaux (ISN). Cette option permet de renforcer la sécurité de certains systèmes d'exploitation ne sachant pas générer d'ISN suffisamment aléatoires. A partir de la version 3.5 d'OpenBSD, l'option modulate state peut être utilisée pour les autres protocoles que TCP.
Pour conserver l'état des connexions TCP, UDP et ICMP tout en renforçant la sécurité des ISN :
pass out on fxp0 proto { tcp, udp, icmp } from any \
to any modulate state
Un des avantages de conserver l'état des connexions tient à ce que les messages ICMP relatifs à celles-ci seront traités comme faisant partie de la connexion. Si des messages ICMP sont émis par une machine pour signaler une congestion par exemple, et que le suivi d'état est utilisé, les messages seront pris en compte et acceptés par le pare-feu. Sans cela, ils auraient été bloqués ou ignorés.
La portée d'une entrée dans la table d'état dépend des options state-policy d'une manière globale ou bien des options if-bound, group-bound et floating-state. Les valeurs appliquées règle par règle ont la même signification que lorsqu'elles sont utilisées avec l'option state-policy. Par exemple :
pass out on fxp0 proto { tcp, udp, icmp } from any \
to any modulate state (if-bound)
Selon cette règle, les paquets ne trouveront une correspondance dans la table d'état que s'ils transitent par l'interface fxp0.
Il faut noter que les règles nat, binat et rdr créent implicitement des entrées dans la table d'état.
Les options sont spécifiées entre parenthèses et tout de suite après l'un des mots-clés de gestion d'état ((keep state, modulate state, ou synproxy state). S'il y a plusieurs options, vous devez les séparer par des virgules. A partir d'OpenBSD 4.1, le mot-clé keep state est utilisé par défaut par toutes les règles de filtrage lorsqu'aucun mot-clé de gestion d'état n'est spécifié. Malgré cela, un de ces mots-clés doit tout de même être spécifié lors de l'utilisation d'options de gestion d'état.
Une règle d'exemple :
pass in on $ext_if proto tcp to $web_server \
port www keep state \
(max 200, source-track rule, max-src-nodes 100, max-src-states 3)
La règle ci-dessus définit le comportement suivant :
Un jeu séparé de restrictions peut être placé sur les connexions TCP stateful qui ont une poignée de main "3-way handshake" complète.
Ces deux options font appel à l'option source-track rule et sont incompatibles avec source-track global.
Ces limites étant placées sur les connexions TCP ayant réalisé la poignée de main TCP, des connexions plus agressives pourront toujours avoir lieu depuis les adresses IP concernées.
Un exemple :
table <abusive_hosts> persist
block in quick from <abusive_hosts>
pass in on $ext_if proto tcp to $web_server \
port www flags S/SA keep state \
(max-src-conn 100, max-src-conn-rate 15/5, overload <abusive_hosts> flush)
Ceci permet de :
Le mot-clef flags doit apparaître dans une règle si l'on souhaite que PF prenne en compte la valeur des drapeaux TCP d'un paquet. La syntaxe est la suivante :
flags check/mask
flags any
La partie mask de la règle indique la liste des drapeaux que PF doit inspecter. La partie check quant à elle spécifie les drapeaux qui doivent être positionnés pour que la règle s'applique au paquet traité. L'utilisation du mot-clé any permet de positionner n'importe quelle combinaison de drapeaux au niveau de l'en-tête.
pass in on fxp0 proto tcp from any to any port ssh flags S/SA
Cette règle s'applique aux paquets TCP dont le drapeau SYN est positionné. PF limite son inspection aux drapeaux SYN et ACK. La règle s'applique donc à un paquet dont les drapeaux SYN et ECE sont positionnés mais pas à un paquet dont les drapeaux SYN et ACK ou dont seul le drapeau ACK sont positionnés.
A partir d'OpenBSD 4.1, les drapeaux appliqués par défaut aux règles TCP sont flags S/SA. Combinés avec le mot-clé keep state positionné par défaut au niveau de toutes les règles de filtrage à partir d'OpenBSD 4.1, les deux règles suivantes deviennent équivalentes :
pass out on fxp0 proto tcp all flags S/SA keep state
pass out on fxp0 proto tcp all
Chaque règle sera activée par les paquets TCP dont le drapeau SYN est positionné et dont le drapeau ACK ne l'est pas et chacune de ces deux règles créera une entrée dans la table d'état pour les paquets correspondants. Les drapeaux par défaut peuvent être contournés en utilisant l'option flags tel que spécifié plus haut.
Jusqu'à OpenBSD 4.0, aucun drapeau n'était positionné par défaut par les règles de filtrage. Chaque règle devait spécifier le(s) drapeau(x) ainsi que l'option keep state.
pass out on fxp0 proto tcp all flags S/SA keep state
Il faut manipuler les drapeaux avec prudence et se méfier des mauvais
conseils. Certaines personnes suggèrent de ne créer des entrées que pour
les paquets dont le drapeau SYN est positionné. Ce qui peut aboutir à
cette règle :
. . . flags S/FSRPAUEW mauvaise pioche !!
En théorie, une session TCP commence par un paquet dont le drapeau SYN est positionné. Toujours en théorie, il ne faut créer une entrée dans la table d'état que pour ce genre de paquets. Mais certains systèmes utilisent le drapeau ECN en début de session. Ces paquets sont rejetés par la règle précédente. Une meilleure solution consiste à ne pas spécifier de drapeau et de laisser PF appliquer les drapeaux par défaut à vos règles. Si vous avez réellement besoin de spécifier des drapeaux vous-même alors cette combinaison devrait être sûre :
. . . flags S/SAFR
Si le trafic est normalisé, il peut être pratique et sûr de ne pas tester la valeur des drapeaux FIN et RST. Dans ce cas, PF rejette tout paquet entrant dont les drapeaux TCP sont positionnés de manière illicite (par exemple SYN et RST) et les combinaisons potentiellement ambiguës (telles que SYN et FIN) seront normalisées.
Normalement, quand un client ouvre une connexion TCP vers un serveur, PF relaie les paquets d'ouverture (handshake) au fur et à mesure qu'ils arrivent. PF peut agir en tant que mandataire (proxy). Dans ce cas, PF va traiter la demande en lieu et place du serveur et ne transfèrera qu'ensuite les paquets à ce dernier. Aucun paquet n'est transmis au serveur avant que le client n'ait terminé l'échange initial (handshake). L'avantage de cette méthode est de protéger le serveur des attaques par inondation de paquets SYN lancées à l'aide de paquets falsifiés.
Le mandataire TCP SYN est activé à l'aide de l'option synproxy state :
pass in on $ext_if proto tcp from any to $web_server port www \
flags S/SA synproxy state
Toutes les connexions à destination du serveur HTTP seront mandatées par PF.
L'option synproxy state apporte les mêmes avantages que les options keep state et modulate state.
Par contre, l'option synproxy ne fonctionne pas quand PF est installé en passerelle transparente (bridge(4)).
PF permet de se prémunir de ce type d'attaques grâce à l'option antispoof :
antispoof [log] [quick] for interface [af]
Exemple:
antispoof for fxp0 inet
Quand les règles sont chargées, toutes les occurrences du mot antispoof sont décodées dans deux filtres. Si l'interface fxp0 dont l'adresse IP est 10.0.0.1 pour un masque de sous- réseau de 255.255.255.0 (soit /24) est protégée, l'option antispoof sera décodée ainsi :
block in on ! fxp0 inet from 10.0.0.0/24 to any
block in inet from 10.0.0.1 to any
Cette règle déclenche deux actions :
REMARQUE : le filtrage activé par l'option antispoof d'une règle s'applique également aux paquets envoyés sur l'adresse de bouclage interne (loopback). Le filtrage est communément désactivé sur ces interfaces, et cela devient primordial lors de l'utilisation de règles antispoof :
set skip on lo0
antispoof for fxp0 inet
L'utilisation de l'option antispoof est réservée aux interfaces qui possèdent une adresse IP. Utiliser antispoof sur une interface sans adresse IP aboutit au filtrage suivant :
block drop in on ! fxp0 inet all
block drop in inet all
Avec ce genre de règles, le risque est réel de bloquer tout le trafic entrant sur toutes les interfaces.
Depuis OpenBSD 4.0, PF offre la fonctionnalité Unicast Reverse Path Forwarding (uRPF). Lorsqu'un paquet est soumis à la vérification uRPF, l'adresse IP source de celui-ci est recherchée dans la table de routage. Si l'interface de sortie trouvée dans la table de routage afin de joindre la source est la même que celle par laquelle le paquet vient d'entrer, le test uRPF réussit. Si les interfaces ne correspondent pas, il est alors possible que le paquet ait une adresse source spoofée.
La vérification uRPF peut être réalisée sur les paquets en utilisant dans les règles de filtrage le mot-clef urpf-failed :
block in quick from urpf-failed label uRPF
Notez que la vérification uRPF n'a de sens que dans un environnement de routage symétrique.
uRPF propose la même fonctionnalité que les règles antispoof.
La reconnaissance passive d'OS par leurs empreintes ("OS Fingerprinting" ou OSFP) est une méthode qui permet de reconnaître à distance quel système d'exploitation tourne sur une machine. Cette reconnaissance se base sur les caractéristiques des paquets TCP SYN renvoyés par une machine. Ces informations peuvent être utilisées comme critères dans des règles de filtrage.
PF utilise le fichier d'empreintes /etc/pf.os pour reconnaître les systèmes d'exploitation auxquels il a affaire. Lorsque PF s'exécute, la liste des empreintes reconnues peut être consultée grâce à la commande suivante :
# pfctl -s osfp
Dans une règle, une empreinte peut être désignée sous la forme d'une classe, d'une version ou d'un sous-type d'OS. La liste de ces éléments est affichée à l'aide de la commande pfctl. Pour désigner une empreinte dans une règle, il faut utiliser le mot-clef os :
pass in on $ext_if from any os OpenBSD keep state
block in on $ext_if from any os "Windows 2000"
block in on $ext_if from any os "Linux 2.4 ts"
block in on $ext_if from any os unknown
unknown est une classe spéciale désignant les systèmes d'exploitation dont l'empreinte n'est pas connue.
Notez bien que :
pass in quick on fxp0 all allow-opts
ext_if = "fxp0"
int_if = "dc0"
lan_net = "192.168.0.0/24"
# Déclaration du tableau référençant toutes les adresses IP affectées au
# pare-feu.
table <firewall> const { self }
# Ne pas filtrer sur l'interface de bouclage
set skip on lo0
# Normalisation de tous les paquets entrants.
scrub in all
# Mise en place d'une politique d'interdiction par défaut.
block all
# Activation de la protection contre l'usurpation sur toutes les
# interfaces.
block in quick from urpf-failed
# Les connexions ssh ne sont autorisées qu'en provenance du réseau local
# et de la machine 192.168.0.15. "block return" provoque l'émission d'un
# paquet TCP RST pour mettre fin aux connexions illicites. "quick"
# assure que cette règle n'est pas contredite par les règles "pass".
block return in quick on $int_if proto tcp from ! 192.168.0.15 \
to $int_if port ssh
# Autoriser le trafic sortant et entrant sur le réseau local.
# ces règles créeront des entrées au niveau de la table d'état étant
# donné que le mot-clé "keep state" est automatiquement appliqué.
pass in on $int_if from $lan_net to any
pass out on $int_if from any to $lan_net
# Autoriser les connexions sortantes tcp, udp et icmp sur l'interface
# externe.
# les connexions tcp seront modulées, et udp/icmp auront un suivi
# d'état.
pass out on $ext_if proto { tcp udp icmp } all modulate state
# Autoriser les connexions ssh sur l'interface externe du moment
# qu'elles ne sont pas destinées au pare-feu lui-même. Journaliser le
# paquet qui initie la session afin de pouvoir déterminer qui s'est
# connecté. Activer un service mandataire SYN.
# Les drapeaux par défaut "S/SA" seront automatiquement appliqués à la
# règle par PF.
pass in log on $ext_if proto tcp from any to ! <firewall> \
port ssh synproxy state
|
[Section précédente : Tables] [Index] [Section suivante : Traduction des Adresses IP ("NAT")]