FireAIs säkerhetsblogg

Av FireAI Security & Research Team · Publicerad

macOS pf-brandväggen: vad den kan göra och varför den inte kan vara din appbrandvägg

macOS pf-brandväggen: vad den kan göra och varför den inte kan vara din appbrandvägg

Varje Mac levereras med två saker som folk kallar "brandväggen". En är applikationsbrandväggen i systeminställningar, en växling per app för inkommande anslutningar. Den andra, tystare är pf, BSD-paketfiltret som macOS ärvde från FreeBSD/OpenBSD-linjen och som Apple själv använder under huven för internetdelning, VPN och NAT. Avancerade användare och administratörer kan prata med den direkt med pfctl, och många guider visar ett pf.conf-utdrag och kallar det en dag. Vad dessa guider sällan förklarar är var pf slutar vara användbar för det de flesta faktiskt vill ha: att titta på och kontrollera vad deras egna appar skickar ut. Det här är ett labb, inte en föreläsning – vi kommer att slå på pf, skriva en regel, läsa tillståndet det behåller och sedan titta på exakt varför det tillståndet är fel form för en appbrandvägg.

Vad pf egentligen är

pf är ett paketfilter på kärnnivå: det inspekterar paket när de korsar nätverksgränssnitt och bestämmer regel för regel om de ska skickas eller blockeras. Den har inget koncept med "appar" - det fungerar enbart på pakethuvuden: käll- och destinationsadress, port, protokoll, gränssnitt, riktning. Det är inte en begränsning som någon glömt att fixa; det är designen. pf byggdes för att filtrera trafik i nätverkslagret, samma lager som routrar och gateways fungerar på, och det är mycket bra på det jobbet.

Du pratar med den med pfctl, kontrollverktyget. Dess man-sida är tydlig om uppdelningen mellan de två sakerna den gör: den laddar regeluppsättningar från en konfigurationsfil, och den rapporterar om tillståndet som kärnan har. Två flaggor är viktigast för att aktivera och inaktivera filtret, med mansidans egna ord: -e ("Aktivera paketfiltret.") och -d ("Avaktivera paketfiltret."). Inget annat om pf är på eller av - hela regeluppsättningen rör sig tillsammans.

Slår på den och läser dess tillstånd

Ett snabbt labb, på en Mac där du är bekväm med att använda sudo. Kontrollera först om filtret redan är aktiverat och se dess räknare:

Terminal — pf-status och räknare
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

Lista sedan reglerna som kärnan för närvarande har. pfctl -s rules gör exakt detta; man-sidan noterar att den med -v också skriver ut antal utvärderingar per regel, paket och byte:

Terminal — för närvarande laddade regler
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

Den com.apple/*-raden är inte dekoration. Apple laddar in sina egna regler i namngivna ankare - pf:s term för en fristående delregeluppsättning som kan bytas in och ut utan att ladda om allt annat. pfctls -a-flagga riktar sig mot ett specifikt ankare och, enligt man-sidan, möjliggör användning av den med ett jokertecken rekursiv utskrift av kapslade ankare, vilket är hur du ser vad Apple själv har laddat tillsammans med allt du lägger till:

Terminal — listar varje laddat ankare rekursivt
sudo pfctl -a '*' -s rules
# example output, trimmed to the anchors that exist on a stock Mac

Att skriva och ladda en testregel

En minimal ankarfil som blockerar en utgående IP-adress, sparad som /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

För att ladda en enskild ankarfil läser pfctl -f regler från en fil, enligt dess man-sida, som beskriver filen som innehållande makron, tabeller, alternativ och filtreringsregler:

Terminal — laddar och bekräftar regeln
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

Varför pf inte kan vara din app-brandvägg

Inget av det som följer är ett fel. Det är vad som händer när du riktar ett nätverkspaketfilter mot ett jobb som kräver att du vet vilken process som skickade paketet.

Den har ingen aning om vilken app som skickade paketet

pf-regler matchar på IP, port, protokoll, gränssnitt och riktning. Det finns inget fält för "processnamn", "buntidentifierare" eller "kodsignatur", eftersom pf sitter på lagret där paket finns men processer inte gör det. Två helt olika appar som öppnar TCP-anslutningar till samma IP och port går inte att skilja åt pf. Om du vill tillåta Slack att nå en värd samtidigt som du blockerar alla andra appar från att nå samma värd, kan inte pf ensam uttrycka den regeln.

En regel för ett värdnamn är en regel för vilken IP som värdnamnet än hade vid laddningstidpunkten

pf.conf-filer refererar ofta till ett värdnamn för läsbarhet — block from evil.example.com. Det som faktiskt laddas är inte det namnet; det är vilken adress det än bestäms till. OpenBSD pf.conf man-sidan säger tydligt detta: "Värdnamnsupplösning och gränssnitt för adressöversättning görs vid regeluppsättningens laddningstid." Det finns ingen runtime DNS-uppslagning när trafiken flyter – ersättningen sker en gång, när du kör pfctl -f, och regeln fortsätter att matcha den adressen tills du laddar om den. Det är bra för en server med en statisk IP. Det faller sönder i samma ögonblick som namnet bakom det är en CDN, en molnbelastningsbalanserare eller någon tjänst som roterar eller lastbalanserar över många adresser – vilket beskriver det mesta av internet 2026. En regel som är avsedd att blockera "den här tjänsten" avsmalnar tyst till "vilken som än en av den tjänstens IP:er råkade svara när jag laddade om alla andra adresser till samma värddator", och trafiken går rakt igenom värdnamnet.

Inga uppmaningar, ingen konversation - bara en statisk regeluppsättning

pf har ingen interaktionsmodell. Den kan inte pausa en anslutning och fråga "Mail vill nå 51.x.x.x på port 993 för första gången — tillåt det?" Antingen matchar den en regel som du redan skrivit, eller så faller den igenom till standardinställningen. Varje beslut måste förutses och skrivas ner i förväg, i IP-och-port-termer, innan trafiken inträffar. Det finns ingen motsvarighet till en första anslutningsuppmaning, eftersom uppmaning kräver att man vet vilken app som frågar, och pf har inte den informationen till att börja med.

Din handskrivna konfiguration överlever inte en uppdatering

Apple behandlar /etc/pf.conf och de ankare som den laddar som systemhanterad konfiguration kopplad till macOS-interna funktioner – internetdelning, VPN, applikationsbrandväggens egna ankare är beroende av det. macOS-uppdateringar är gratis att skriva om eller ersätta den filen. Om du har redigerat det för att lägga till dina egna regler, finns det ingen garanti för att de överlever nästa uppdatering; du får reda på den hårda vägen, i efterhand, att din regel tyst slutade gälla. En konfigurationsfil som en person underhåller för hand och som operativsystemet regelbundet skriver över är ett dåligt ställe att behålla det du faktiskt brydde dig om - "pratade min Mac med den adressen igen."

Ingen loggvisare, ingen historik, ingen karta

pf kan logga matchade paket till ett pseudogränssnitt, pflog0, om en regel innehåller nyckelordet log — synligt ovan i blocklistregeln från den tidigare -s rules-utdatan. Men den loggen är en paketfångstström, läsbar med tcpdump -i pflog0, inte en sökbar historik. Det finns ingen inbyggd visningsprogram, ingen lista per app över vad som blockerades och när, inget land eller organisation kopplat till en adress, inget du skulle visa någon att svara på "vad försökte den här Macen nå förra veckan." Du får råpaket och resten får du bygga själv.

Lagret som Apple faktiskt byggde för det här jobbet

Apples eget svar på "Jag vill filtrera min Macs trafik per app" är inte pf - det är Network Extension-ramverket, specifikt dess innehållsfilterleverantörer. Apples utvecklardokumentation beskriver modellen direkt: "Ett nätverksinnehållsfilter på enheten undersöker användarnätverksinnehåll när det passerar genom nätverksstacken och avgör om det ska blockera innehållet eller tillåta det att skicka vidare till sin slutdestination", och en filterdataleverantör - en NEFilterDataProvider - ​​"tar emot användarnätverksinnehåll och undersöker innehållet för att avgöra om det ska blockeras eller tillåtas." Flöden representeras som NEFilterFlow-objekt (med NEFilterBrowserFlow och NEFilterSocketFlow som konkreta fall), vilket är den saknade biten som pf aldrig hade: ett flödesobjekt som en filtreringsapp kan inspektera och koppla tillbaka till processen som öppnade den, innan den bestämmer sig för att passera eller blockera.

Det är också därför den inbyggda applikationsbrandväggen (växlingen i systeminställningar) är ett annat djur än pf, inte ett gränssnitt för det. Apples egen guide beskriver det endast i inkommande termer: den "kan skydda din Mac från oönskad kontakt som initieras av andra datorer", och den fungerar genom att låta dig "välja appar och tjänster och ange om de kan ha åtkomst via brandväggen." Per app, ja - men bara för anslutningar som kommer in, och endast genom den specifika mekanism som Apple byggt för det ena jobbet. Den svarar på en annan fråga än "vad skickar min app ut."

Tre sätt att filtrera trafik på en Mac och vad var och en faktiskt vet
Närma sigSer IP/portVet vilken appHanterar omdöpta/roterande IP-adresserKan fråga användarenRiktning
pf (pfctl)JaIngaNej — löstes en gång vid laddningstidIngaAntingen enligt regel
Programbrandvägg (systeminställningar)Nej (växling på appnivå)JaN/AIngaEndast inkommande
Innehållsfilter för nätverkstilläggJaJa, via flödesobjektetJa — utvärderad per liveflödeJa, av appen som är byggd på denUtgående och inkommande

Inget av detta gör pf värdelöst. Om du kör en Mac som en lätt router, behöver avvisa ett känt-dåligt intervall på kärnnivån oavsett vilken process som frågar, eller vill förstå vad Apples egna internetdelnings- och VPN-funktioner gör under huven, är pf det rätta och enda verktyget för det jobbet, och pfctl -s rules / -s info är rätt sätt att se på det. Vad det aldrig skulle göra är att svara på frågan de flesta faktiskt har: vilken av mina appar pratar med vem, just nu, och kan jag bli tillfrågad innan en ny kommer till.

Var FireAI och HisnLabs kommer in

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 är HisnLabs eget verktyg: en AI-brandvägg som körs direkt på din Mac. Den visar varje anslutning dina appar gör, på klarspråk, och låter dig avgöra vad som lämnar din Mac — AI:n körs lokalt, så din trafik skickas aldrig till oss eller någon annan. HisnLabs säkerhetsforskningsteam är de som håller de bedömningarna tillförlitliga: de katalogiserar vilka domäner som är vanlig telemetri och vilka som är en riktig tjänst, spårar land och nätverk bakom en anslutning och tränar den lokala modellen (Autopilot-funktionen) på verkliga trafikmönster — utan att något av det lämnar din Mac.

Du kan läsa om de tekniska besluten bakom, eller prova FireAI i 17 dagar, på FireAI, från HisnLabs.

Källor