Le blog sécurité de FireAI

Par FireAI Security & Research Team · Publié

Le pare-feu macOS pf : ce qu'il peut faire et pourquoi il ne peut pas être votre pare-feu d'application

Le pare-feu macOS pf : ce qu'il peut faire et pourquoi il ne peut pas être votre pare-feu d'application

Chaque Mac est livré avec deux choses que les gens appellent « le pare-feu ». L’un d’entre eux est le pare-feu d’application dans les paramètres système, une bascule par application pour les connexions entrantes. L'autre, plus silencieux, est pf, le filtre de paquets BSD dont macOS a hérité de la lignée FreeBSD/OpenBSD et qu'Apple lui-même utilise sous le capot pour le partage Internet, le VPN et le NAT. Les utilisateurs expérimentés et les administrateurs peuvent lui parler directement avec pfctl, et de nombreux guides affichent un extrait de code pf.conf et l'appellent un jour. Ce que ces guides expliquent rarement, c'est où pf cesse d'être utile pour ce que la plupart des gens veulent réellement : regarder et contrôler ce que leurs propres applications envoient. Il s'agit d'un laboratoire, pas d'une conférence : nous allons activer pf, écrire une règle, lire l'état qu'elle conserve, puis examiner exactement pourquoi cet état n'a pas la bonne forme pour un pare-feu d'application.

Qu'est-ce que pf en réalité

pf est un filtre de paquets au niveau du noyau : il inspecte les paquets lorsqu'ils traversent les interfaces réseau et décide, règle par règle, de les transmettre ou de les bloquer. Il n'a aucun concept d'« applications » — il fonctionne uniquement sur les en-têtes de paquets : adresse source et destination, port, protocole, interface, direction. Ce n’est pas une limitation que quelqu’un a oublié de corriger ; c'est la conception. pf a été conçu pour filtrer le trafic au niveau de la couche réseau, sur laquelle fonctionnent les mêmes routeurs et passerelles, et il est très bon dans ce travail.

Vous lui parlez avec pfctl, l'utilitaire de contrôle. Sa page de manuel est explicite sur la répartition entre les deux choses qu'il fait : il charge les ensembles de règles à partir d'un fichier de configuration et il rend compte de l'état du noyau. Deux indicateurs sont les plus importants pour activer et désactiver le filtre, selon les propres mots de la page de manuel : -e (« Activer le filtre de paquets. ») et -d (« Désactiver le filtre de paquets. »). Rien d'autre dans pf n'est activé ou désactivé - l'ensemble des règles se déplace ensemble.

L'allumer et lire son état

Un atelier rapide, sur un Mac où vous êtes à l'aise avec sudo. Tout d'abord, vérifiez si le filtre est déjà activé et voyez ses compteurs :

Terminal — état pf et compteurs
sudo pfctl -s info
# example output, trimmed — the real thing includes per-rule and per-source-tracking stats with -v
Status: Enabled for 0 days 02:14:07		Debug: err
State Table                          Total             Rate
  current entries                       42
  searches                           88213             9.7/s
  inserts                              611             0.1/s
  removals                             569             0.1/s

Ensuite, listez les règles actuellement détenues par le noyau. pfctl -s rules fait exactement cela ; la page de manuel indique qu'avec -v, elle imprime également le nombre d'évaluations, les paquets et les octets par règle :

Terminal – règles actuellement chargées
sudo pfctl -s rules
# example output, trimmed
scrub-anchor "com.apple/*" all fragment reassemble
anchor "com.apple/*" all
block drop in log quick from <blocklist> to any

Cette ligne com.apple/* n'est pas une décoration. Apple charge ses propres règles dans des ancres nommées – terme utilisé par pf pour désigner un sous-ensemble de règles autonome qui peut être échangé sans recharger tout le reste. L'indicateur -a de pfctl cible une ancre spécifique et, selon la page de manuel, son utilisation avec un caractère générique permet l'impression récursive d'ancres imbriquées, c'est ainsi que vous voyez ce qu'Apple lui-même a chargé à côté de tout ce que vous ajoutez :

Terminal - répertoriant chaque ancre chargée de manière récursive
sudo pfctl -a '*' -s rules
# example output, trimmed to the anchors that exist on a stock Mac

Ecrire et charger une règle de test

Un fichier d'ancrage minimal qui bloque une adresse IP sortante, enregistré sous /etc/pf.anchors/test-block :

/etc/pf.anchors/test-block
block drop out quick on en0 proto tcp to 203.0.113.10 port 443

Pour charger un seul fichier d'ancrage, pfctl -f lit les règles d'un fichier, selon sa page de manuel, qui décrit le fichier comme contenant des macros, des tables, des options et des règles de filtrage :

Terminal — chargement et confirmation de la règle
sudo pfctl -f /etc/pf.anchors/test-block
sudo pfctl -s rules
block drop out quick on en0 proto tcp from any to 203.0.113.10 port = 443

Pourquoi pf ne peut pas être votre pare-feu d'application

Rien de ce qui suit n’est un bug. C'est ce qui se produit lorsque vous dirigez un filtre de paquets de couche réseau vers une tâche qui nécessite de savoir quel processus a envoyé le paquet.

Il n'a aucune idée de l'application qui a envoyé le paquet

Les règles pf correspondent sur l'IP, le port, le protocole, l'interface et la direction. Il n'y a pas de champ pour "nom du processus", "identifiant du bundle" ou "signature de code", car pf se trouve au niveau de la couche où les paquets existent mais pas les processus. Deux applications complètement différentes ouvrant des connexions TCP sur la même adresse IP et le même port ne se distinguent pas par pf. Si vous souhaitez autoriser Slack à atteindre un hôte tout en empêchant toutes les autres applications d'atteindre ce même hôte, pf seul ne peut pas exprimer cette règle.

Une règle sur un nom d'hôte est une règle sur l'adresse IP de ce nom d'hôte au moment du chargement.

Les fichiers pf.conf font souvent référence à un nom d'hôte pour plus de lisibilité - block from evil.example.com. Ce qui est réellement chargé, ce n'est pas ce nom ; c'est l'adresse à laquelle il a été résolu. La page de manuel d'OpenBSD pf.conf le dit clairement : "La résolution du nom d'hôte et la traduction de l'interface vers l'adresse sont effectuées au moment du chargement de l'ensemble de règles." Il n'y a pas de recherche DNS à l'exécution pendant que le trafic circule : la substitution se produit une fois, lorsque vous exécutez pfctl -f, et la règle continue de correspondre à cette adresse jusqu'à ce que vous la rechargez. C'est bien pour un serveur avec une adresse IP statique. Il s'effondre dès que le nom derrière lui est un CDN, un équilibreur de charge cloud ou tout autre service qui tourne ou équilibre la charge sur de nombreuses adresses - ce qui décrit la majeure partie d'Internet en 2026. Une règle destinée à bloquer "ce service" se limite discrètement à "l'adresse IP de ce service qui répond lorsque j'ai chargé la règle", et le trafic vers toutes les autres adresses portant le même nom d'hôte se résout à naviguer directement.

Pas d'invite, pas de conversation : juste un ensemble de règles statiques

pf n'a pas de modèle d'interaction. Il ne peut pas suspendre une connexion et demander « Mail veut atteindre 51.x.x.x sur le port 993 pour la première fois – l'autoriser ? Soit elle correspond à une règle que vous avez déjà écrite, soit elle devient la règle par défaut. Chaque décision doit être anticipée et écrite à l'avance, en termes d'IP et de port, avant que le trafic n'ait lieu. Il n'existe pas d'équivalent à une invite de première connexion, car l'invite nécessite de savoir quelle application demande, et pf ne dispose pas de cette information pour commencer.

Votre configuration manuscrite ne survit pas à une mise à jour

Apple traite /etc/pf.conf et les ancres qu'il charge comme une configuration gérée par le système liée aux composants internes de macOS – le partage Internet, le VPN, les propres ancres du pare-feu d'application en dépendent tous. Les mises à jour macOS sont gratuites pour réécrire ou remplacer ce fichier. Si vous l'avez modifié manuellement pour ajouter vos propres règles, il n'y a aucune garantie qu'elles survivent à la prochaine mise à jour ; vous découvrez à vos dépens, après coup, que votre règle a silencieusement cessé de s'appliquer. Un fichier de configuration qu'une personne gère à la main et que le système d'exploitation écrase périodiquement n'est pas un bon endroit pour conserver la seule chose qui vous tient réellement à cœur : "est-ce que mon Mac a de nouveau parlé à cette adresse".

Pas de visionneuse de journaux, pas d'historique, pas de carte

pf peut enregistrer les paquets correspondants sur une pseudo-interface, pflog0, si une règle inclut le mot-clé log — visible ci-dessus dans la règle de liste de blocage de la sortie précédente -s rules. Mais ce journal est un flux de capture de paquets, lisible avec tcpdump -i pflog0, et non un historique consultable. Il n'y a pas de visionneuse intégrée, pas de liste par application de ce qui a été bloqué et quand, aucun pays ou organisation attaché à une adresse, rien que vous pourriez montrer à quelqu'un pour répondre "qu'est-ce que ce Mac a essayé d'atteindre la semaine dernière". Vous obtenez des paquets bruts et vous construisez le reste vous-même.

La couche qu'Apple a réellement construite pour ce travail

La réponse d'Apple à la question "Je souhaite filtrer le trafic de mon Mac par application" n'est pas pf : il s'agit du framework Network Extension, en particulier de ses fournisseurs de filtrage de contenu. La documentation du développeur d'Apple décrit directement le modèle : "Un filtre de contenu réseau sur l'appareil examine le contenu du réseau de l'utilisateur lorsqu'il traverse la pile réseau et détermine s'il doit bloquer ce contenu ou lui permettre de le transmettre à sa destination finale", et un fournisseur de données de filtre - un NEFilterDataProvider - ​​"reçoit le contenu du réseau de l'utilisateur et examine ce contenu pour déterminer s'il doit le bloquer ou l'autoriser." Les flux sont représentés sous forme d'objets NEFilterFlow (avec NEFilterBrowserFlow et NEFilterSocketFlow comme cas concrets), ce qui est la pièce manquante que pf n'a jamais eu : un objet de flux qu'une application de filtrage peut inspecter et relier au processus qui l'a ouvert, avant de décider de l'accepter ou de le bloquer.

C'est également pourquoi le pare-feu d'application intégré (la bascule dans les paramètres système) est un animal différent de pf, pas une interface pour celui-ci. Le propre guide d'Apple le décrit uniquement en termes entrants : il "peut protéger votre Mac contre les contacts indésirables initiés par d'autres ordinateurs", et il fonctionne en vous permettant de "sélectionner des applications et des services, et de spécifier s'ils peuvent y accéder via le pare-feu". Par application, oui, mais uniquement pour les connexions entrantes, et uniquement via le mécanisme spécifique conçu par Apple pour cette tâche. Il répond à une question différente de "Qu'est-ce que mon application envoie".

Trois façons de filtrer le trafic sur un Mac et ce que chacune sait réellement
ApprocheVoit IP/portSait quelle applicationGère les adresses IP renommées/rotativesPeut inviter l'utilisateurDirection
pf (pfctl)OuiNonNon - résolu une fois au moment du chargementNonSoit, par règle
Pare-feu d'application (paramètres système)Non (bascule au niveau de l'application)OuiN / ANonEntrant uniquement
Filtre de contenu d'extension réseauOuiOui, via l'objet fluxOui — évalué par flux en directOui, grâce à l'application créée dessusSortant et entrant

Rien de tout cela ne rend pf inutile. Si vous utilisez un Mac en tant que routeur léger, que vous devez rejeter une plage connue comme étant mauvaise au niveau du noyau, quel que soit le processus demandé, ou que vous souhaitez comprendre ce que font les fonctionnalités de partage Internet et VPN d'Apple sous le capot, pf est le bon et le seul outil pour ce travail, et pfctl -s rules / -s info sont la bonne façon de l'envisager. Ce qu'il n'allait jamais faire, c'est répondre à la question que la plupart des gens se posent réellement : laquelle de mes applications parle à qui, en ce moment, et peut-on me le demander avant qu'une nouvelle n'y parvienne.

Le rôle de FireAI et de HisnLabs

pf and the built-in Application Firewall are both worth using — FireAI does not replace either; it fills the specific gap neither one can, by tying outbound decisions to the app’s code signature and asking before an unknown one gets a first connection.

FireAI est le produit de HisnLabs : un pare-feu IA embarqué pour Mac. Il montre en langage clair chaque connexion faite par vos applications et vous laisse décider ce qui sort de votre Mac — son IA fonctionne en local, votre trafic ne nous est jamais envoyé, ni à personne d’autre. L’équipe de recherche en sécurité de HisnLabs est celle qui garde ces décisions fiables : elle recense les domaines de simple télémétrie face à ceux d’un vrai service, suit le pays et le réseau derrière une connexion, et entraîne le modèle embarqué (la fonction Autopilot) sur du trafic réel, sans que rien ne quitte votre Mac.

Vous pouvez lire les choix techniques qui s’y trouvent, ou essayer FireAI pendant 17 jours, sur FireAI, par HisnLabs.

Sources