O blog de segurança da FireAI

Por FireAI Security & Research Team · Publicado

O firewall pf do macOS: o que ele consegue fazer, e por que não pode ser o seu firewall de aplicativos

O firewall pf do macOS: o que ele consegue fazer, e por que não pode ser o seu firewall de aplicativos

Todo Mac vem com duas coisas que as pessoas chamam de "o firewall". Uma é o Firewall de Aplicativos nos Ajustes do Sistema, um interruptor por aplicativo para conexões de entrada. A outra, mais discreta, é o pf, o filtro de pacotes BSD que o macOS herdou da linhagem FreeBSD/OpenBSD e que a própria Apple usa por baixo dos panos para compartilhamento de internet, VPN e NAT. Usuários avançados e administradores conseguem conversar diretamente com ele usando o pfctl, e muitos guias mostram um trecho de pf.conf e encerram por ali. O que esses guias raramente explicam é onde o pf deixa de ser útil para o que a maioria das pessoas de fato quer: observar e controlar o que seus próprios aplicativos enviam para fora. Este é um laboratório, não uma palestra — vamos ativar o pf, escrever uma regra, ler o estado que ele mantém, e depois examinar exatamente por que esse estado é o formato errado para um firewall de aplicativos.

O que o pf de fato é

O pf é um filtro de pacotes em nível de kernel: ele inspeciona pacotes ao atravessarem interfaces de rede e decide, regra por regra, se deve deixá-los passar ou bloqueá-los. Ele não tem nenhum conceito de "aplicativos" — trabalha puramente com cabeçalhos de pacote: endereço de origem e destino, porta, protocolo, interface, direção. Isso não é uma limitação que alguém esqueceu de corrigir; é o design. O pf foi construído para filtrar tráfego na camada de rede, a mesma camada em que roteadores e gateways operam, e ele é muito bom nesse trabalho.

Você conversa com ele usando o pfctl, o utilitário de controle. Sua página de manual é explícita sobre a divisão entre as duas coisas que ele faz: carrega conjuntos de regras a partir de um arquivo de configuração, e relata o estado que o kernel está mantendo. Duas flags importam mais para ativar e desativar o filtro, nas palavras da própria página de manual: -e ("Ativa o filtro de pacotes.") e -d ("Desativa o filtro de pacotes."). Nada mais no pf é ligado ou desligado individualmente — o conjunto de regras inteiro se move junto.

Ativando e lendo seu estado

Um laboratório rápido, em um Mac onde você está confortável usando sudo. Primeiro, verifique se o filtro já está ativado e veja seus contadores:

Terminal — status e contadores do pf
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

Depois, liste as regras que o kernel mantém atualmente. pfctl -s rules faz exatamente isso; a página de manual observa que, com -v, também imprime contagens de avaliação por regra, pacotes e bytes:

Terminal — regras atualmente carregadas
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

Essa linha com.apple/* não é decoração. A Apple carrega suas próprias regras em anchors nomeadas — o termo do pf para um subconjunto de regras autocontido que pode ser trocado sem recarregar tudo o mais. A flag -a do pfctl mira em uma anchor específica e, segundo a página de manual, usá-la com um coringa ativa a impressão recursiva de anchors aninhadas, que é como você vê o que a própria Apple carregou junto com qualquer coisa que você adicionar:

Terminal — listando toda anchor carregada recursivamente
sudo pfctl -a '*' -s rules
# example output, trimmed to the anchors that exist on a stock Mac

Escrevendo e carregando uma regra de teste

Um arquivo mínimo de anchor que bloqueia um endereço IP na saída, salvo como /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

Para carregar um único arquivo de anchor, pfctl -f lê regras de um arquivo, segundo sua página de manual, que descreve o arquivo como contendo macros, tabelas, opções e regras de filtragem:

Terminal — carregando e confirmando a regra
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

Por que o pf não pode ser o seu firewall de aplicativos

Nada do que segue é um bug. É o que acontece quando você aponta um filtro de pacotes da camada de rede para um trabalho que exige saber qual processo enviou o pacote.

Ele não tem ideia de qual aplicativo enviou o pacote

As regras do pf correspondem por IP, porta, protocolo, interface e direção. Não existe campo para "nome do processo", "identificador de bundle" ou "assinatura de código", porque o pf fica na camada onde pacotes existem, mas processos não. Dois aplicativos completamente diferentes abrindo conexões TCP para o mesmo IP e porta são indistinguíveis para o pf. Se você quiser permitir que o Slack alcance um host enquanto bloqueia todo outro aplicativo de alcançar esse mesmo host, o pf sozinho não consegue expressar essa regra.

Uma regra sobre um nome de host é uma regra sobre qualquer IP que esse nome tinha no momento do carregamento

Arquivos pf.conf costumam referenciar um nome de host por legibilidade — block from evil.example.com. O que de fato é carregado não é esse nome; é o endereço para o qual ele resolveu. A página de manual do pf.conf do OpenBSD diz isso claramente: "a resolução de nome de host e a tradução de interface para endereço são feitas no momento do carregamento do conjunto de regras." Não há consulta DNS em tempo real enquanto o tráfego flui — a substituição acontece uma vez, quando você roda pfctl -f, e a regra continua correspondendo a esse único endereço até você recarregá-la. Isso é ótimo para um servidor com IP estático. Desmorona no momento em que o nome por trás dele é uma CDN, um balanceador de carga na nuvem, ou qualquer serviço que gira ou balanceia entre muitos endereços — o que descreve a maior parte da internet em 2026. Uma regra pensada para bloquear "este serviço" silenciosamente se estreita para "qual quer que fosse o IP desse serviço que respondeu quando carreguei a regra", e o tráfego para todo outro endereço para o qual o mesmo nome de host resolve passa direto.

Sem avisos, sem conversa — apenas um conjunto de regras estático

O pf não tem nenhum modelo de interação. Ele não consegue pausar uma conexão e perguntar "o Mail quer alcançar 51.x.x.x na porta 993 pela primeira vez — permitir?" Ou ele corresponde a uma regra que você já escreveu, ou cai no padrão. Toda decisão precisa ser antecipada e escrita com antecedência, em termos de IP e porta, antes de o tráfego acontecer. Não existe nenhum equivalente a um aviso de primeira conexão, porque avisar exige saber qual aplicativo está pedindo, e o pf simplesmente não tem essa informação de início.

Sua configuração escrita à mão não sobrevive a uma atualização

A Apple trata o /etc/pf.conf e as anchors que ele carrega como configuração gerenciada pelo sistema, atrelada a componentes internos do macOS — o compartilhamento de internet, a VPN e as próprias anchors do Firewall de Aplicativos dependem disso. As atualizações do macOS têm liberdade para reescrever ou substituir esse arquivo. Se você o editou manualmente para adicionar suas próprias regras, não há garantia de que elas sobrevivam à próxima atualização; você descobre isso da forma difícil, depois do fato, que sua regra silenciosamente parou de se aplicar. Um arquivo de configuração que uma pessoa mantém manualmente e que o sistema operacional periodicamente sobrescreve é um péssimo lugar para guardar a única coisa com a qual você realmente se importava — "meu Mac voltou a falar com aquele endereço."

Sem visualizador de logs, sem histórico, sem mapa

O pf consegue registrar pacotes correspondidos em uma pseudo-interface, pflog0, se uma regra incluir a palavra-chave log — visível acima na regra de lista de bloqueio da saída anterior de -s rules. Mas esse log é um fluxo de captura de pacotes, legível com tcpdump -i pflog0, não um histórico pesquisável. Não há visualizador embutido, nenhuma lista por aplicativo do que foi bloqueado e quando, nenhum país ou organização anexado a um endereço, nada que você mostraria a alguém para responder "com o que este Mac tentou se conectar na semana passada." Você recebe pacotes brutos, e cabe a você construir o resto.

A camada que a Apple de fato construiu para esse trabalho

A resposta da própria Apple para "eu quero filtrar o tráfego do meu Mac por aplicativo" não é o pf — é o framework Network Extension, especificamente seus provedores de filtro de conteúdo. A documentação para desenvolvedores da Apple descreve o modelo diretamente: "um filtro de conteúdo de rede no dispositivo examina o conteúdo de rede do usuário conforme ele passa pela pilha de rede e determina se deve bloquear esse conteúdo ou permitir que siga até seu destino final", e um provedor de dados de filtro — um NEFilterDataProvider — "recebe o conteúdo de rede do usuário e examina esse conteúdo para determinar se deve bloquear ou permitir." Os fluxos são representados como objetos NEFilterFlow (com NEFilterBrowserFlow e NEFilterSocketFlow como casos concretos), que é a peça que faltava e que o pf nunca teve: um objeto de fluxo que um aplicativo de filtragem consegue inspecionar e vincular de volta ao processo que o abriu, antes de decidir deixar passar ou bloquear.

É também por isso que o Firewall de Aplicativos embutido (o interruptor nos Ajustes do Sistema) é um animal diferente do pf, não uma interface para ele. O próprio guia da Apple o descreve apenas em termos de entrada: ele "pode proteger seu Mac de contato indesejado iniciado por outros computadores", e funciona permitindo que você "selecione aplicativos e serviços, e especifique se eles podem ter acesso através do firewall." Por aplicativo, sim — mas apenas para conexões chegando, e apenas por meio do mecanismo específico que a Apple construiu para esse único trabalho. Ele responde a uma pergunta diferente de "o que o meu aplicativo está enviando para fora."

Três formas de filtrar tráfego em um Mac, e o que cada uma de fato sabe
AbordagemVê IP/portaSabe qual aplicativoLida com IPs renomeados/rotativosConsegue avisar o usuárioDireção
pf (pfctl)SimNãoNão — resolvido uma vez no carregamentoNãoQualquer uma, por regra
Firewall de Aplicativos (Ajustes do Sistema)Não (interruptor em nível de aplicativo)SimN/ANãoSomente entrada
Filtro de conteúdo do Network ExtensionSimSim, via o objeto de fluxoSim — avaliado por fluxo ao vivoSim, pelo aplicativo construído sobre eleSaída e entrada

Nada disso torna o pf inútil. Se você usa um Mac como um roteador leve, precisa rejeitar uma faixa conhecidamente ruim no nível do kernel independentemente de qual processo está pedindo, ou quer entender o que os próprios recursos de compartilhamento de internet e VPN da Apple estão fazendo por baixo dos panos, o pf é a ferramenta certa e única para esse trabalho, e pfctl -s rules / -s info são a forma certa de examiná-lo. O que ele nunca conseguiria fazer é responder à pergunta que a maioria das pessoas de fato tem: qual dos meus aplicativos está falando com quem, agora mesmo, e posso ser consultado antes de um novo conseguir isso.

Onde FireAI e HisnLabs entram nessa história

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.

O FireAI é o produto da HisnLabs: um firewall com IA que roda direto no seu Mac. Ele mostra, em linguagem simples, cada conexão que seus aplicativos fazem e deixa você decidir o que sai do seu Mac — a IA roda localmente, então seu tráfego nunca é enviado para nós nem para ninguém. A equipe de pesquisa em segurança da HisnLabs é quem mantém essas decisões confiáveis: cataloga quais domínios são telemetria comum e quais são um serviço de verdade, rastreia o país e a rede por trás de uma conexão e treina o modelo local (o recurso Autopilot) com padrões reais de tráfego, sem que nada disso saia do seu Mac.

Você pode ler as decisões técnicas por trás dele, ou testar o FireAI por 17 dias, em FireAI, da HisnLabs.

Fontes