[Section précédente : Tables]
[Index]
[Section suivante : Traduction des Adresses IP ("NAT")]
PF : Le Filtrage de Paquets
Table des Matières
Introduction
Le filtrage de paquets à l'aide de
pf(4)
consiste à autoriser ou bloquer le trafic réseau en fonction des
propriétés des protocoles des couches 3
(IPv4 et
IPv6) et 4
(TCP,
UDP,
ICMP et
ICMPv6).
Les adresses et ports source et destination ainsi que les protocoles
utilisés sont des critères fréquemment employés.
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-clé 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).
Syntaxe
L'écriture des règles obéit à la syntaxe très simplifiée suivante
:
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]
- action
- Ce mot-clé indique le type d'action associé à tout paquet
correspondant aux critères contenus dans la règle. Les deux valeurs
possibles sont pass et block. pass signifie
que le paquet sera transféré au noyau pour être traité. Le blocage du
paquet (block) sera fonction de la politique définie par les
options
block-policy. L'action
associée par défaut peut être modifiée en spécifiant block drop
ou block return.
- direction
- Ce mot-clé spécifie le sens du trafic vu depuis l'interface réseau
: celui-ci peut être entrant (in) ou sortant (out).
- log
- La présence de ce mot-clé dans une règle déclenche la
journalisation des paquets correspondants à la règle grâce à
l'utilitaire
pflogd(8).
Si la règle crée un état, seul le paquet correspondant à l'ouverture de
la session est conservé. Pour conserver tous les paquets d'une session,
il faut utiliser le mot-clé log (all).
- quick
- Si le mot-clé quick est utilisé dans une règle, celle-ci
est considérée comme étant la dernière à prendre en compte et
l'action spécifiée est prise.
- interface
- Le nom ou le groupe de l'interface sur laquelle le paquet
transite. Les interfaces peuvent être ajoutées à des groupes arbitraires
en utilisant la commande
ifconfig(8).
Plusieurs groupes sont également automatiquement créés par le noyau :
- Le groupe egress, qui contient la/les interface(s)
relative(s) à la route par défaut.
- Les groupes par famille pour les interfaces clonables.
Par exemple : ppp ou carp.
Ceci causerait la correspondance de la règle pour tout paquet traversant
respectivement une interface ppp ou carp.
- af
- Il est possible de spécifier la famille d'adresses IP à laquelle
appliquer une règle à l'aide de ce mot-clé. Les deux valeurs possibles
sont inet pour les adresses IPv4 et inet6 pour
IPv6. PF peut généralement déterminer à quelle famille appartient un
paquet à partir de ses adresses source et destination.
- protocol
- Ce mot-clé identifie les protocoles de couche 4 utilisés. Il peut
prendre les valeurs suivantes :
- tcp
- udp
- icmp
- icmp6
- tout protocole spécifié dans le fichier
/etc/protocols
- le numéro d'un protocole compris entre 0 et 255
- un ensemble de protocoles passé dans une
liste.
- src_addr, dst_addr
- Ces mots-clefs identifient respectivement les adresses source et
destination du paquet telles que contenues dans son en-tête IP. Ces
adresses peuvent être spécifiées :
- sous la forme d'adresse IPv4 ou IPv6.
- sous la forme d'un bloc d'adresses
CIDR.
- sous la forme d'un domaine. Ce dernier fera l'objet d'une résolution
DNS lors du chargement des règles par PF. La règle s'appliquera
alors à toutes les adresses du domaine.
- par l'intermédiaire du nom d'une interface réseau. Toute adresse IP
affectée à cette interface sera valide pour la règle.
- par l'intermédiaire du nom d'une interface réseau suivi d'un /netmask
(par exemple /24). Toutes les adresses IP
correspondant au bloc CIDR formé par l'adresse IP de l'interface et le
masque de sous réseau seront valides pour cette règle.
- sous la forme du nom d'une interface réseau mis entre parenthèses
( ). Cette mise en forme indique à PF qu'il doit mettre ses
règles à jour en cas de changement de l'adresse IP affectée à
l'interface en question. Cette technique est très utile dans le cas
de liaisons PPP ou d'utilisation du protocole DHCP pour
l'attribution d'adresses IP. Elle évite d'avoir à recharger les
règles à chaque nouvelle affectation.
- grâce au nom d'une interface suivi d'un des paramètres suivants :
- :network - identifie un bloc CIDR (par exemple :
192.168.0.0/24)
- :broadcast - identifie une adresse de multi-diffusion
(par exemple : 192.168.0.255)
- :peer - identifie l'adresse d'un pair sur un lien point à
point.
- De plus, le paramètre :0 peut être ajouté aussi bien au
nom d'une interface qu'à chacun des paramètres présentés
ci-dessus. PF ne prend alors pas en compte les éventuels alias
d'adresses IP affectés à l'interface. Ces paramètres peuvent
aussi être utilisés dans le cas d'une interface entre parenthèses.
Par exemple: fxp0:network:0
- à l'aide d'une table.
- Le mot-clé urpf-failed peut être utilisé au niveau de
l'adresse source pour indiquer si elle doit ou non subir une vérification uRPF.
- sous toutes les formes décrites ci-dessus précédées du paramètre
d'inversion ! ("not").
- à l'aide d'une liste d'adresses.
- grâce au mot-clé any qui identifie n'importe quelle
adresse.
- grâce au mot-clé all qui est un raccourci pour
l'expression from any to any (n'importe quelle source vers
n'importe quelle destination).
- src_port, dst_port
- Ces mots-clefs identifient respectivement les ports source et
destination qui apparaissent dans les en-têtes des protocoles de
couche 4. Ces ports peuvent être spécifiés :
- sous forme numérique par un nombre compris entre 1 et 65535.
- par le nom d'un service tel qu'identifié dans le fichier
/etc/services.
- sous la forme d'une liste.
- sous la forme d'un intervalle de ports construit à l'aide des
opérateurs suivants :
- != (différent)
- < (inférieur à)
- > (supérieur à)
- <= (inférieur ou égal à)
- >= (supérieur ou égal à)
- >< (intervalle)
- <> (intervalle inverse)
- Les deux derniers opérateurs demandent deux arguments pour
former un intervalle qui n'inclut pas ces arguments.
- : (intervalle complet)
- L'opérateur d'intervalle complet est également un opérateur binaire
incluant les arguments dans l'intervalle.
- tcp_flags
- Spécifie les drapeaux qui doivent être activés dans l'en-tête TCP lors de
l'utilisation de proto tcp. Cette valeur est spécifiée ainsi :
flags check/mask. Par exemple : flags S/SA.
Dans ce cas, PF teste uniquement la valeur des drapeaux S et A (SYN et ACK)
pour savoir si le drapeau SYN est positionné (et est appliqué à toutes
les règles TCP par défaut).
flags any indique à PF de ne pas vérifier les drapeaux.
- state
- Ce mot-clé indique dans quel état doit être le paquet pour
satisfaire à une règle.
- no state - fonctionne avec TCP, UDP et ICMP.
PF ne suivra pas cette connexion avec état.
Pour les connexions TCP, flags any est aussi généralement
nécessaire.
- keep state - s'applique aux protocoles TCP, UDP et ICMP.
Cette option est appliquée par défaut à toutes les règles de filtrage.
- modulate state - ne s'applique qu'au protocole TCP. PF
renforcera le caractère aléatoire des numéros de séquence initiaux
(ISN) générés pour ces paquets.
- synproxy state - PF agit comme mandataire pour les
connexions TCP entrantes. Cela renforce la protection contre les
attaques par inondation de paquets SYN en provenance d'adresses
usurpées. Cette option active implicitement les fonctionnalités
keep state et modulate state.
Blocage par défaut
Il est recommandé d'adopter une approche de blocage par défaut lors de
la configuration d'un pare-feu. Cela signifie que tout est
interdit et que l'on autorise le trafic au cas par cas. Cette approche
est assimilable à l'application d'un principe de précaution et simplifie
l'écriture des règles.
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.
Laisser passer le trafic
Une fois notre politique restrictive mise en place, il faut spécifier
quelles sont les connexions autorisées. C'est là qu'entrent en jeu les
critères décrits précédemment : adresse et port source et destination,
protocole, etc... Chaque fois qu'un paquet est autorisé à franchir les
murs du pare-feu, les règles correspondantes devront être les plus
restrictives possibles : il s'agit de n'autoriser que le trafic voulu et
lui seul.
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
L'option quick
Comme nous l'avons vu, chaque paquet est testé au regard de toutes les
règles de filtrage, de la première à la dernière. Par défaut, un paquet
est marqué à chaque test. Le résultat final peut ainsi changer d'une
règle à l'autre jusqu'à ce que toutes aient été parcourues. Rappelons
que c'est la dernière règle à laquelle correspond un paquet qui
l'emporte sur les autres. Il y a cependant une exception : si l'option
quick est présente dans une règle et qu'un paquet correspond
aux critères de cette règle, il n'y a plus de tests : la règle en
question est alors considérée par PF comme étant la dernière. Les
exemples suivants illustrent ce cas de figure :
Mauvais :
block in on fxp0 proto tcp 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 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
Une des fonctionnalités les plus importantes de PF est sa capacité à
conserver l'état des connexions. PF est capable d'évaluer un paquet non
plus unitairement mais dans le contexte de la connexion à laquelle il
appartient. PF utilise pour cela une table d'état grâce à laquelle PF
peut rapidement déterminer si un paquet fait partie d'une connexion déjà
établie et autorisée. Si tel est le cas, le paquet est transféré sans
test complémentaire.
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.
Toutes les règles pass créent de manière automatique une entrée
dans la table d'état dès qu'un paquet les active.
Cela peut-être désactivé de manière explicite en utilisant l'option
no state.
pass out on fxp0 proto tcp from any to any
Cette règle autorise 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. Pour
simplifier les règles, l'option modulate state peut être utilisée
pour les autres protocoles que TCP, dans les autres cas elle est traitée
comme keep state.
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.
Conserver l'état des connexions UDP
On entend souvent dire qu'il est impossible d'utiliser la table d'état
avec UDP car c'est un protocole sans état. S'il est vrai qu'une
connexion UDP n'utilise pas stricto sensu le concept d'état tel que le
fait une connexion TCP (à savoir une ouverture et une terminaison
explicites de la connexion), cela n'a aucune conséquence sur la capacité
qu'a PF de créer et gérer des états pour les connexions UDP. Pour ce
type de protocole sans début/fin de connexion explicite, PF
conserve simplement une trace de la durée d'une session. S'il s'écoule
un certain laps de temps sans échange de paquets entre les deux parties,
l'entrée associée à la session dans la table d'état est supprimée.
Ce laps de temps peut être configuré dans la section
options du fichier pf.conf.
Options de Suivi Stateful
Les règles de filtrage qui créent une entrée dans la table d'états
peuvent spécifier plusieurs options afin de contrôler le comportement de
ces créations d'états.
Les options suivantes sont disponibles :
- max number
- Limite le nombre maximum d'entrées d'états que la règle peut créer à
number.
Si le maximum est atteint, les paquets qui devraient normalement créer
un état sont rejetés jusqu'à ce que le nombre d'états existants soit en
dessous de la limite.
- no state
- Empêche la règle de créer automatiquement une entrée dans la table
d'état.
- source-track
- Cette option active le suivi du nombre d'états créés par adresse IP
source.
Cette option a deux formats :
- source-track rule - Le nombre maximum d'états créés
par cette règle est limité par les options max-src-nodes
et max-src-states de la règle. Seules les
entrées d'états crées par cette règle particulière comptent
pour la limite des règles.
- source-track global - Le nombre d'états créés par
toutes les règles qui utilisent cette option est limité.
Chaque règle peut spécifier différentes options max-src-nodes
et max-src-states, cependant, les entrées
d'états crées par toute règle participante comptent en vue
d'une limite individuelle éventuelle.
Le nombre total d'adresses IP source suivies globalement peut être
contrôlé via l'option
src-nodes runtime.
- max-src-nodes nombre
- Lorsque l'option source-track est utilisée,
max-src-nodes limitera le nombre d'adresses IP source pouvant
créer simultanément une entrée.
Cette option peut seulement être utilisée avec une option source-track.
- max-src-states nombre
- Lorsque l'option source-track est utilisée,
max-src-states limitera le nombre d'entrées d'états
simultanées pouvant être crées par adresse IP source.
La portée de cette limite (les états créés par cette règle uniquement ou
les états créés par toutes les règles utilisant source-track)
est dépendante de l'option source-track spécifiée.
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 :
- Limiter le nombre maximum absolu d'états pouvant être créés par
cette règle à 200
- Activer le suivi de la source; limiter la création d'états pour
cette règle uniquement
- Limiter le nombre maximum de nuds pouvant simultanément créer des
états à 100
- Limiter le nombre maximum d'états simultanés par adresse IP source à
3
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.
- max-src-conn nombre
- Limiter le nombre maximum de connexions TCP simultanées ayant
réalisé la poignée de main qu'un hôte peut initier.
- max-src-conn-rate nombre / intervalle
- Limiter le taux de nouvelles connexions à un certaine fréquence.
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.
- overload <table>
- Mettre l'adresse d'un hôte concerné dans la table désignée.
- flush [global]
- Tue toutes les autres connexions qui correspondent à cette règle et
qui ont été créées par cette adresse IP source.
Quand global est spécifié, cela tue tous les états
correspondant à cette adresse IP source, sans discernement de la règle
qui a créé cet état.
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 :
- Limiter le nombre maximum de connexions par source à 100
- Limiter le taux du nombre de connexions à 15 dans une durée de 5
secondes
- Mettre l'adresse IP de tout hôte qui dépasse ces limites dans la
table <abusive_hosts>
- Pour des adresses IP concernées, supprimer tous les états créés par
cette règle.
Les drapeaux TCP
On utilise souvent les drapeaux TCP dans des règles pour traiter les
ouvertures de sessions. Ces drapeaux et leur signification sont
présentés dans la liste suivante :
- F : FIN - Fin de session
- S : SYN - Synchronize ; correspond à une ouverture de session
- R : RST - Reset ; met fin à une session
- P : PUSH - Push ; le paquet est envoyé immédiatement
- A : ACK - Acknowledgement ; atteste de l'acquittement d'une
des parties
- U : URG - Urgent
- E : ECE - Explicit Congestion Notification Echo ; avis de congestion
- W : CWR - Congestion Window Reduced ; avis de réduction de la
fenêtre TCP
Le mot-clé 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
pass in on fxp0 proto tcp from any to any port ssh
Comme les drapeaux S/SA sont définis par défaut, les règles
précédentes sont équivalentes, chacune des ces règles s'applique au trafic
TCP avec le drapeau SYN positionné en regardant uniquement les drapeaux SYN
et ACK.
Un paquet avec les drapeaux SYN et ECE s'appliquera aux règles précédentes,
mais pas à un paquet dont les drapeaux SYN et ACK ou dont seul le
drapeau ACK sont positionnés.
Les drapeaux par défaut peuvent être contournés en utilisant l'option
flags tel que spécifié plus haut.
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.
Mandataire TCP SYN
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).
Dans le cas d'attaques par inondation de paquets SYN, les paquets de
l'attaquant n'atteignent jamais le serveur protégé, mais les clients
légitimes termineront la liaison et passeront.
Cela minimise l'impact d'inondations TCP SYN spoofées sur le service
protégé, en les gérant directement dans PF. Cependant, l'utilisation
systématique de cette option n'est pas recommandée, étant donné qu'elle
rompt le comportement prévu du protocole TCP lorsque le serveur ne peut
traiter la requête et lorsque les équilibreurs de charges sont actifs.
Le mandataire TCP SYN est activé à l'aide de l'option synproxy
state :
pass in on $ext_if proto tcp to $web_server port www 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)).
Bloquer les paquets usurpés
On parle d'usurpation quand un utilisateur mal intentionné maquille son
adresse IP dans le but d'anonymiser ou de cacher son identité afin de
lancer des attaques sans que leur origine soit détectable. Il peut
également essayer et parfois réussir à avoir accès à des services
réservés à certaines adresses.
PF permet de se prémunir de ce type d'attaques grâce à l'option
antispoof :
antispoof [log] [quick] for interface [af]
- log
- Journalise les paquets via
pflogd(8).
- quick
- Si un paquet correspond à la règle, celle-ci est appliquée
immédiatement.
- interface
- Désigne l'interface sur laquelle s'applique la protection. Il est
possible de passer une liste
d'interfaces en paramètre.
- af
- Spécifie le type d'adresse : inet pour IPv4 ou
inet6 pour IPv6.
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 :
- elle bloque tout le trafic en provenance du réseau 10.0.0.0/24 s'il
ne passe pas par l'interface fxp0. Puisque le réseau
10.0.0.0/24 est branché sur l'interface fxp0, aucun paquet en
provenance de celui-ci ne devrait arriver ailleurs.
- elle bloque tout le trafic entrant dont l'adresse source est
10.0.0.1, à savoir celle de l'interface fxp0. Cette machine
ne devrait en effet jamais émettre de paquets à travers une
interface externe et par conséquent ne doit pas recevoir de paquets
ayant son adresse IP comme adresse source.
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.
Unicast Reverse Path Forwarding
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-clé 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.
Reconnaissance passive d'OS par leurs empreintes
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-clé os :
pass in on $ext_if proto tcp from any os OpenBSD keep state
block in on $ext_if proto tcp from any os "Windows 2000"
block in on $ext_if proto tcp from any os "Linux 2.4 ts"
block in on $ext_if proto tcp 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 :
- La reconnaissance peut échouer face à des paquets spécifiquement
construits pour tromper la détection d'empreintes.
- L'application de correctifs peut modifier le comportement de la
pile TCP/IP d'un système d'exploitation et faire également échouer
ou tromper la reconnaissance de l'OS.
- L'option OSFP n'est applicable qu'aux paquets TCP SYN. Elle est
inefficace avec d'autres protocoles et pour les sessions déjà
établies.
Les options IP
PF bloque par défaut tous les paquets qui utilisent les options IP. Cela
rend moins aisé le travail des outils de reconnaissance d'empreintes
tels que nmap. Si une application utilise ces options (par exemple IGMP
ou les diffusions multicast) il est possible d'utiliser l'option
allow-opts :
pass in quick on fxp0 all allow-opts
Exemple de règles de filtrage
Vous trouverez ci-dessous un exemple de règles de filtrage pour un
pare-feu PF destiné à protéger un petit réseau connecté à Internet. Seules
les règles de filtrage sont mentionnées ;
queueing,
nat,
rdr, etc...
ont été volontairement laissées de côté.
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.
match in all scrub (no-df)
# 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
pass out on $int_if 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, plus tard,
# qui a essayé de se connecter.
# Décommentez la dernière partie pour utiliser le proxy tcp syn.
pass in log on $ext_if proto tcp to ! <firewall> \
port ssh # synproxy state
|
[Section précédente : Tables]
[Index]
[Section suivante : Traduction des Adresses IP ("NAT")]
www@openbsd.org
$OpenBSD: filter.html,v 1.54 2012/11/02 07:24:05 ajacoutot Exp $