Tutorial

Como configurar o Packet Filter (PF) no FreeBSD 12.1

SecurityFirewallFreeBSD

O autor selecionou a COVID-19 Relief Fund​​​​​ para receber uma doação como parte do programa Write for DOnations.

Introdução

O firewall é, provavelmente, uma das linhas de defesa mais importantes contra os ataques cibernéticos. A capacidade de configurar um firewall do zero é uma habilidade capacitadora que permite que administradores assumam o controle de suas redes.

O Packet Filter (PF) é um aplicativo de firewall renomado mantido pelo OpenBSD, um projeto orientado para segurança. Ele é mais precisamente apresentado como uma ferramenta de filtragem de pacotes, por isso o seu nome, e ele é conhecido por sua sintaxe simples, amigável e de recursos amplos. O PF é um firewall dinâmico por padrão, que armazena as informações sobre conexões em uma state table, que pode ser acessada para fins analíticos. O PF faz parte do sistema base do FreeBSD e tem suporte de uma comunidade forte de desenvolvedores. Embora haja diferenças entre as versões do FreeBSD e do OpenBSD do PF relacionadas às arquiteturas de kernel, em geral, suas sintaxes são semelhantes. Dependendo da complexidade, o conjunto de regras comuns pode ser modificado para funcionar em uma das distribuições facilmente.

Neste tutorial, você construirá um firewall do zero em um servidor FreeBSD 12.1 com PF. Você projetará um conjunto de regras base que pode ser usado como modelo para projetos futuros. Você também explorará algumas das funcionalidades avançadas do PF, como a higiene de pacotes, a prevenção de força bruta, o monitoramento e a geração de registros, bem como outras ferramentas de terceiros.

Pré-requisitos

Antes de começar este tutorial, você precisará do seguinte:

  • Um servidor 1G FreeBSD 12.1 (ZFS ou UFS). Você pode usar nosso tutorial de Introdução ao FreeBSD para definir o servidor com sua configuração preferida.
  • O FreeBSD não tem um firewall habilitado por padrão. A personalização é uma marca da FreeBSD eethos. Portanto, quando inicializar seu servidor pela primeira vez, será necessária uma proteção temporária enquanto o PF estiver sendo configurado. Caso esteja usando a DigitalOcean, habilite seu firewall em nuvem imediatamente após inicializar o servidor. Consulte o Guia de início rápido do Firewall para instruções sobre como configurar um firewall em nuvem. Antes de começar, caso esteja usando outro provedor em nuvem, defina a rota mais rápida para uma proteção imediata. Qualquer que seja o método que escolha, seu firewall temporário deve permitir apenas o tráfego SSH de entrada e pode permitir todos os tipos de tráfego de saída.

Passo 1 — Compilando seu conjunto de regras preliminar

Você iniciará este tutorial elaborando um conjunto de regras preliminar, que fornece proteção básica e acesso a serviços cruciais da Internet. Neste ponto, você tem um servidor FreeBSD 12.1 em execução com um firewall em nuvem ativo.

Há duas abordagens para a construção de um firewall: default deny (negação padrão) e default permit (permissão padrão). A negação padrão bloqueia todo o tráfego e permite apenas o que está especificado em uma regra. A permissão padrão faz exatamente o oposto: ela passa todo o tráfego e bloqueia apenas o que está especificado em uma regra. Você usará o padrão de negação.

As regras do PF são escritas em um arquivo de configuração chamado /etc/pf.conf, que também é sua localização padrão. Não há problema em armazenar este arquivo em outro lugar, desde que ele esteja especificado no arquivo de configuração /etc/rc.conf. Neste tutorial, você usará a versão padrão.

Faça o login no seu servidor com seu usuário não raiz:

  • ssh freebsd@your_server_ip

Em seguida, crie seu arquivo /etc/pf.conf:

  • sudo vi /etc/pf.conf

Nota: caso queira ver o conjunto de regras base completo a qualquer momento no tutorial, consulte os exemplos do Passo 4 ou Passo 8.

O PF filtra pacotes de acordo com três ações principais: block, pass e match. Quando combinadas com outras opções, elas formam regras. Uma ação é tomada quando um pacote cumpre os critérios especificados em uma regra. Como era de se esperar, as regras pass e block irão passar, por meio de pass, e bloquear, por meio de block, o tráfego. Uma regra match executa uma ação em um pacote quando ele encontra um critério de correspondência, mas não os passa ou bloqueia. Por exemplo, você pode realizar network address translation (conversão de endereços de rede) (NAT) em um pacote de correspondência sem passar ou bloqueá-lo, e ele ficará lá até que você diga a ele para fazer algo em outra regra, como encaminhá-lo para outra máquina ou gateway.

Em seguida, adicione a primeira regra ao seu arquivo /etc/pf.conf:

/etc/pf.conf
block all

Esta regra bloqueia todas as formas de tráfego em todas as direções. Uma vez que a regra não especifica uma direção, ela é padronizada para in e out. Esta regra é legítima para uma estação de trabalho local que precisa ser isolada do mundo, mas ela é, em grande parte, impraticável e não funcionará em um servidor remoto, pois ela não permite o tráfego SSH. Na verdade, se tivesse habilitado o PF, seu acesso ao servidor estaria bloqueado.

Revise seu arquivo /etc/pf.conf para permitir o tráfego SSH com a linha destacada a seguir:

/etc/pf.conf
block all
pass in proto tcp to port 22

Nota: de maneira alternativa, utilize o nome do protocolo:

/etc/pf.conf
block all
pass in proto tcp to port ssh

Por uma questão de consistência, usaremos números de porta, a menos que haja uma razão válida para não usarmos. Recomendamos que veja uma lista detalhada de protocolos e seus respectivos números de porta no arquivo /etc/services.

O PF processa as regras em sequência, de cima para baixo. Portanto, seu conjunto de regras atual inicialmente bloqueia todo o tráfego. Em seguida, o PF transmite o tráfego se o critério de correspondência na próxima linha for atendido. Neste caso, o critério em questão é o tráfego SSH.

Agora, é possível usar o SSH em seu servidor, mas você ainda está bloqueando todas as formas de tráfego de saída. Isto é um problema, pois você não pode acessar serviços essenciais da Internet para instalar pacotes, atualizar suas definições de data/hora e assim por diante.

Para resolver isso, adicione a seguinte regra destacada ao final do seu arquivo /etc/pf.conf:

/etc/pf.conf
block all
pass in proto tcp to port { 22 }
pass out proto { tcp udp } to port { 22 53 80 123 443 }

Seu conjunto de regras agora permite o tráfego de saída SSH, DNS, HTTP, NTP e HTTPS, assim como o bloqueio de todo o tráfego interno (com a exceção do SSH). Coloque os números de porta e protocolos dentro de colchetes, que formam uma lista de sintaxe PF. Isso permite que você adicione mais números de porta caso seja necessário. Também adicione uma regra de senha para o protocolo UDP nas portas 53 e 123, pois o DNS e o NTP frequentemente alternam entre os protocolos TCP e UDP. O conjunto de regras preliminar está quase finalizado. Você só precisa adicionar algumas regras para obter a funcionalidade básica.

Complete o conjunto de regras preliminar com as regras destacadas:

Preliminary Ruleset /etc/pf.conf
set skip on lo0
block all
pass in proto tcp to port { 22 }
pass out proto { tcp udp } to port { 22 53 80 123 443 }
pass out inet proto icmp icmp-type { echoreq }

Salve e saia do arquivo.

Crie uma regra de set skip para o dispositivo de loopback, pois não é necessário que ele filtre o tráfego, e isso provavelmente causaria lentidão no seu servidor. Adicione uma regra de pass out inet para o protocolo ICMP, que permitirá que você utilize o utilitário ping(8) para solução de problemas. A opção inet representa a família de endereço do IPv4.

O ICMP é um protocolo de mensagem multipropósito usado pelos dispositivos de rede para vários tipos de comunicação. O utilitário ping, por exemplo, utiliza um tipo de mensagem conhecido como echo request, que você adicionou à sua lista icmp_type. Como uma medida de precaução, permita apenas os tipos de mensagem necessários. Essa medida evitará que dispositivos indesejados entrem em contato com seu servidor. À medida que suas necessidades aumentam, você pode adicionar mais tipos de mensagem à sua lista.

Você tem agora um conjunto de regras em funcionamento, que fornece funcionalidades básicas para a maioria das máquinas. Na próxima seção, confirmaremos que tudo está funcionando corretamente, habilitando o PF e testando seu conjunto de regras preliminar.

Passo 2 — Testando seu conjunto de regras preliminar

Neste passo, você testará seu conjunto de regras preliminar e fará a transição do seu firewall em nuvem para seu firewall PF, permitindo que o PF assuma completamente. Você ativará seu conjunto de regras com o utilitário pfctl, que é a ferramenta de linha de comando integrada do PF, e o método primário de interface com o PF.

Os conjuntos de regras do PF nada mais são que arquivos de texto, o que significa que não existem procedimentos delicados envolvidos no carregamento de um novo conjunto de regras. Carregue um novo conjunto de regras. Isso fará o conjunto antigo ser removido. Raramente é necessário recarregar um conjunto de regras existente.

O FreeBSD utiliza uma Web de scripts shell conhecida como sistema rc para gerenciar a maneira como os serviços são iniciados no momento da inicialização; especificamos esses serviços em vários arquivos de configuração do rc. Para serviços globais como o PF, utilize o arquivo /etc/rc.conf. Como os arquivos rc são cruciais para o bem estar de um sistema FreeBSD, eles não devem ser editados diretamente. Em vez disso, o FreeBSD fornece um utilitário de linha de comando conhecido como sysrc, projetado para ajudar você a editar esses arquivos com segurança.

Vamos habilitar o PF usando o utilitário de linha de comando sysrc:

  • sudo sysrc pf_enable="YES"
  • sudo sysrc pflog_enable="YES"

Verifique essas alterações, imprimindo o conteúdo do seu arquivo /etc/rc.conf:

  • sudo cat /etc/rc.conf

Você verá o seguinte resultado:

Output
pf_enable="YES" pflog_enable="YES"

Habilite também o serviço pflog, que por sua vez, habilita o daemon pflogd para o registro em log em PF (você trabalhará com o registro em log em um passo mais adiante).

Especifique dois serviços globais em seu arquivo /etc/rc.conf. Eles não inicializarão até você reinicializar o servidor ou inicializá-los manualmente. Reinicie o servidor para que você possa testar seu acesso SSH.

Inicie o PF reinicializando o servidor:

  • sudo reboot

A conexão cairá. Espere alguns minutos para atualizar.

Agora, conecte-se novamente ao servidor com SSH:

  • ssh freebsd@your_server_ip

Embora tenha inicializado seus serviços do PF, você ainda não carregou seu conjunto de regras /etc/pf.conf. Isso significa que seu firewall ainda não está ativo.

Carregue o conjunto de regras com o pfctl:

  • sudo pfctl -f /etc/pf.conf

Se não houver erros ou mensagens, o conjunto de regras não tem erros e o firewall está ativo.

Agora que o PF está funcionando, desanexe o servidor do firewall em nuvem. Isso pode ser realizado no painel de controle em sua conta da DigitalOcean, removendo o Droplet do portal do firewall em nuvem. Se estiver usando outro provedor em nuvem, sua proteção temporária deve estar desabilitada . Executar dois firewalls diferentes em um servidor quase certamente gerará problemas.

Como medida de precaução, reinicie seu servidor novamente:

  • sudo reboot

Após alguns minutos, conecte-se novamente ao servidor via SSH:

  • ssh freebsd@your_server_ip

O PF agora é seu firewall em funcionamento. É possível garantir que ele esteja em execução acessando alguns dados com o utilitário pfctl.

Vamos visualizar algumas estatísticas e contadores com o pfctl -si:

  • sudo pfctl -si

Passe os sinalizadores -si, que significam show info. Esta é uma das várias combinações de parâmetro de filtragem que você pode usar com o pfctl para analisar dados sobre sua atividade de firewall.

Você verá os seguintes dados tabulares (os valores variarão de máquina para máquina):

Output
Status: Enabled for 0 days 00:01:53 Debug: Urgent State Table Total Rate current entries 5 searches 144 1.3/s inserts 11 0.1/s removals 6 0.1/s Counters match 23 0.2/s bad-offset 0 0.0/s fragment 0 0.0/s short 0 0.0/s normalize 0 0.0/s memory 0 0.0/s bad-timestamp 0 0.0/s congestion 0 0.0/s ip-option 0 0.0/s proto-cksum 0 0.0/s state-insert 0 0.0/s state-limit 0 0.0/s src-limit 0 0.0/s synproxy 0 0.0/s map-failed 0 0.0/s

Como acabou de ativar seu conjunto de dados, você ainda não verá muitas informações. No entanto, este resultado mostra que o PF já registrou 23 regras correspondentes, o que significa que os critérios do seu conjunto de regras foram correspondidos 23 vezes. O resultado também confirma que seu firewall está funcionando.

Seu conjunto de regras também permite que o tráfego de saída acesse alguns serviços cruciais da Internet, incluindo o utilitário ping.

Vamos verificar a conectividade com a Internet e o serviço DNS com um ping no google.com:

  • ping -c 3 google.com

Como você executou o sinalizador de contagem -c 3, verá três respostas de conexão bem-sucedidas:

Output
PING google.com (172.217.0.46): 56 data bytes 64 bytes from 172.217.0.46: icmp_seq=0 ttl=56 time=2.088 ms 64 bytes from 172.217.0.46: icmp_seq=1 ttl=56 time=1.469 ms 64 bytes from 172.217.0.46: icmp_seq=2 ttl=56 time=1.466 ms --- google.com ping statistics --- 3 packets transmitted, 3 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 1.466/1.674/2.088/0.293 ms

Confirme que você consegue acessar o repositório pkgs com o seguinte comando:

  • sudo pkg upgrade

Caso houver atualizações para alguns pacotes, atualize-os.

Se ambos os serviços estiverem funcionando, seu firewall está funcionando e você pode agora prosseguir. Embora seu conjunto de regras preliminar forneça proteção e funcionalidade, ele ainda é um conjunto de regras elementar e pode ser melhorado. Nas seções restantes, você completará seu conjunto de regras base e usará algumas das funcionalidades avançadas do PF.

Passo 3 — Concluindo seu conjunto de regras base

Neste passo, você aprimorará o conjunto de regras preliminar para completar seu conjunto de regras base. Você reorganizará algumas das suas regras e trabalhará com conceitos mais avançados.

Incorporando macros e tabelas

Em seu conjunto de regras preliminar, você codificou todos os seus parâmetros em cada regra, ou seja, os números de porta que compõem as listas. Dependendo de suas redes,isso pode se tornar impraticável no futuro. Para fins de organização, o PF inclui macros, lists e tables. Você já incluiu listas diretamente em suas regras. Porém, você também pode separá-las de suas regras e atribuí-las a uma variável usando macros.

Abra o arquivo para transferir alguns de seus parâmetros para macros:

  • sudo vi /etc/pf.conf

Adicione o conteúdo seguinte para o topo do conjunto de regras:

/etc/pf.conf
vtnet0 = "vtnet0"
icmp_types = "{ echoreq }"
. . .

Modifique as regras de SSH e ICMP anteriores com suas novas variáveis:

/etc/pf.conf
. . .
pass in on $vtnet0 proto tcp to port { 22 }
. . .
pass inet proto icmp icmp-type $icmp_types
. . .

Agora, suas regras de SSH e ICMP anteriores usam macros. Os nomes das variáveis são denotados pela sintaxe de sinal de dólar do PF. Atribua sua interface vtnet0 a uma variável com o mesmo nome apenas por formalidade. Isso dá a você a opção de renomear a interface no futuro, caso seja necessário. Os nomes $pub_if ou $ext_if são outros nomes de variáveis comuns para as interfaces voltadas ao público.

Em seguida, você implementará uma table semelhante a um macro, porém, ela é projetada para reter grupos de endereços IP. Vamos criar uma tabela para endereços IP não roteáveis, que geralmente têm um papel no denial of service attacks (ataques de negação de serviço) (DOS). Use os endereços IP especificados no RFC6890, que define registros de endereço IP de finalidades especiais. Seu servidor não deve enviar pacotes para esses endereços ou receber pacotes deles através da interface voltada ao público.

Crie esta tabela adicionando o conteúdo seguinte diretamente abaixo do macro icmp_types:

/etc/pf.conf
. . .
table <rfc6890> { 0.0.0.0/8 10.0.0.0/8 100.64.0.0/10 127.0.0.0/8 169.254.0.0/16          \
                  172.16.0.0/12 192.0.0.0/24 192.0.0.0/29 192.0.2.0/24 192.88.99.0/24    \
                  192.168.0.0/16 198.18.0.0/15 198.51.100.0/24 203.0.113.0/24            \
                  240.0.0.0/4 255.255.255.255/32 }
. . .

Agora, adicione suas regras para a tabela <rfc6890> abaixo da regra set skip on lo0:

/etc/pf.conf
. . .
set skip on lo0
block in quick on egress from <rfc6890>
block return out quick on egress to <rfc6890>
. . .

Aqui, introduza a opção return, que complementa sua regra block out. Isto baixará os pacotes e também enviará uma RST message para o host que tentou fazer essas conexões, o que é útil para analisar a atividade do host. Em seguida, adicione a palavra-chave egress, que encontra automaticamente as default routes(s) em qualquer interface. Normalmente, este é um método mais limpo de encontrar rotas padrão, especialmente com redes complexas. A palavra-chave quick executa as regras imediatamente, sem considerar o resto do conjunto de regras. Por exemplo, caso um pacote com um endereço IP inconsistente tente se conectar ao servidor, você deve desativar a conexão imediatamente, e não haverá motivo para executar esse pacote para o restante do conjunto de regras.

Protegendo suas portas SSH

Como sua porta SSH está aberta ao público, ela está sujeita a exploração. Um dos sinais de aviso mais claros de um invasor é a quantidade em massa de tentativas de login. Por exemplo, caso o mesmo endereço IP tente fazer login em seu servidor dez vezes em um segundo, presuma que ele não tenha sido feito alguém pessoalmente, mas sim por software de computador que tentava decifrar sua senha de login. Esses tipos de explorações sistemáticas são frequentemente conhecidos como ataques de brute force (força bruta) e geralmente são bem-sucedidos se o servidor tiver senhas fracas.

Aviso: recomendamos fortemente a autenticação de chave pública em todos os servidores. Consulte o tutorial da DigitalOcean a respeito da autenticação baseada em chaves.

O PF possui recursos integrados para o tratamento de ataques de força bruta e outros ataques semelhantes. Com o PF, você pode limitar o número de tentativas de conexões simultâneas permitidas por um único host. Caso um host exceda esses limites, a conexão cairá, e eles serão banidos do servidor. Para realizar isso, você usará o overload mechanism (mecanismo de sobrecarga) do PF, que possui uma tabela de endereços IP proibidos.

Modifique sua regra SSH anterior para limitar o número de conexões simultâneas de um único host, conforme as instruções seguintes:

/etc/pf.conf
. . .
pass in on $vtnet0 proto tcp to port { 22 } \
    keep state (max-src-conn 15, max-src-conn-rate 3/1, \
        overload <bruteforce> flush global)
. . .

Adicione a opção de keep state, que permite que você defina os critérios de estado para a tabela de sobrecarga. Passe o parâmetro max-src-conn para especificar o número de conexões simultâneas permitidas de um único host por segundo, e o parâmetro max-src-conn-rate para especificar o número de novas conexões permitidas de um único host por segundo. Especifique 15 conexões para o max-src-conn e 3 conexões para o max-src-conn-rate. Caso esses limites sejam ultrapassados por um host, o mecanismo de overload adiciona o IP da fonte à tabela <bruteforce>, que os proíbe do servidor. Por fim, a opção flush global derruba a conexão imediatamente.

Você definiu uma tabela de sobrecarga em sua regra SSH, mas ainda não declarou a tabela em seu conjunto de regras.

Adicione a tabela <bruteforce> abaixo da macro icmp_types:

/etc/pf.conf
. . .
icmp_types = "{ echoreq }"
table <bruteforce> persist
. . .

A palavra-chave persist permite que uma tabela vazia exista no conjunto de regras. Sem a palavra-chave, o PF acusará que não existem endereços IP na tabela.

Essas medidas garantem que sua porta SSH esteja protegida por um mecanismo de segurança poderoso. O PF permite que você configure soluções rápidas para se proteger de tipos graves de exploração. Nas próximas seções, você seguirá alguns passos para limpar os pacotes assim que eles chegarem ao seu servidor.

Limpando seu tráfego

Nota: as seções a seguir descrevem os fundamentos básicos do conjunto de protocolo TCP/IP. Caso esteja planejando desenvolver aplicativos Web ou redes, é de seu total interesse dominar estes conceitos. Consulte o tutorial de Introdução à terminologia de redes, interfaces e protocolos da Digital Ocean.

Devido à complexidade do conjunto de protocolos TCP/IP e a perseverança de atores mal-intencionados, os pacotes frequentemente chegam com discrepâncias e ambiguidades, como fragmentos de sobreposição IP, endereços de IP falsos e mais. É imperativo que você limpe seu tráfego antes que ele entre no sistema. O termo técnico para este processo é normalization (normalização).

Quando os dados viajam pela Internet, eles normalmente são divididos em fragmentos menores para se acomodarem aos parâmetros de transmissão do host de destino, onde eles serão reunidos em pacotes completos. Infelizmente, um invasor pode sequestrar este processo de diversas maneiras que estão além do escopo deste tutorial. No entanto, com o PF, você pode gerenciar a fragmentação com uma regra. O PF inclui uma palavra-chave scrub, que normaliza os pacotes.

Adicione a palavra-chave scrub diretamente antes de sua regra block all:

/etc/pf.conf
. . .
set skip on lo0
scrub in all fragment reassemble max-mss 1440
block all
. . .

Essa regra aplica a depuração em todo o tráfego de entrada. Inclua a opção fragment reassemble, que impede que fragmentos entrem no sistema. Em vez disso, eles são armazenados na memória até que eles sejam reunidos em pacotes completos, o que significa que suas regras de filtragem terão que lidar apenas com pacotes uniformes. Inclua também a opção max-mss 1440, que representa o maximum segment size (tamanho máximo de segmento) de pacotes TCP reunidos, também conhecidos como payload. Especifique um valor de 1440 bytes, que atinge um equilíbrio entre o tamanho e o desempenho, deixando bastante espaço para os cabeçalhos.

Outro aspecto importante da fragmentação é um termo conhecido como maximum transmission unit (unidade de transmissão máxima) ou MTU. Os protocolos TCP/IP permitem que os dispositivos negociem os tamanhos de pacotes para fazer conexões. O host de destino utiliza as mensagens de ICMP para informar o IP de origem de sua MTU, um processo conhecido como MTU path discovery. O tipo de mensagem específico de ICMP é o destination unreachable (destino inacessível). Você habilitará a MTU path discovery adicionando o tipo de mensagem unreach para sua lista de icmp_types.

Você usará a MTU padrão de 1500 bytes do seu servidor, que pode ser determinada com o comando ifconfig:

  • ifconfig

Você verá o seguinte resultado, que inclui sua atual MTU:

Output
vtnet0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500 options=6c07bb<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,JUMBO_MTU,VLAN_HWCSUM,TSO4,TSO6,LRO,VLAN_HWTSO,LINKSTATE,RXCSUM_IPV6,TXCSUM_IPV6> . . .

Atualize a lista icmp_types para incluir o tipo de mensagem destination unreachable:

/etc/pf.conf
vtnet0 = "vtnet0"
icmp_types = "{ echoreq unreach}"
. . .

Agora que você tem as políticas prontas para lidar com a fragmentação, os pacotes que entram em seu sistema serão uniformes e consistentes. Isso é desejável pelo fato de existirem muitos dispositivos que trocam dados pela Internet.

Agora, você trabalhará para prevenir outro problema de segurança, conhecido como IP spoofing. Os invasores frequentemente mudam seus IPs de origem para parecerem que residem em um nó de confiança dentro de uma organização. O PF inclui uma diretiva de antispoofing para lidar com IPs de origem falsa. Ao ser aplicada a uma interface específica, a antifalsificação bloqueia todo o tráfego da rede da interface (a menos que ele seja originário dela). Por exemplo, caso você aplique a antifalsificação a uma interface que reside em 5.5.5.1/24, todo o tráfego da rede 5.5.5.0/24 não poderá se comunicar com o sistema, a menos que ele seja originário da mesma interface.

Adicione o conteúdo destacado seguinte para aplicar a antifalsificação em sua interface vtnet0:

/etc/pf.conf
. . .
set skip on lo0
scrub in
antispoof quick for $vtnet0
block all
. . .

Salve e saia do arquivo.

Essa regra de antifalsificação diz que todo o tráfego da rede do vtne0 pode passar apenas pela interface vtnet0, ou ele será descartado imediatamente com a palavra-chave quick. Os atores proibidos não poderão se esconder na rede do vtnet0 e não poderão se comunicar com outros nós.

Para demonstrar sua regra de antifalsificação, você imprimirá seu conjunto de regras na tela em formato detalhado. As regras em PF são normalmente escritas em formato abreviado, porém, elas também podem ser escritas em formato detalhado. Geralmente, escrever regras desta maneira é impraticável, mas, para fins de teste, pode ser útil.

Imprima em tela os conteúdos de /etc/pf.conf usando o pfctl com o seguinte comando:

  • sudo pfctl -nvf /etc/pf.conf

Este comando pfctl recebe os sinalizadores -nvf, que imprimem o conjunto de regras e os testa, sem carregar nada. Isto também é conhecido como dry run. Agora, você verá todo o conteúdo de /etc/pf.conf em seu formato detalhado.

Você verá algo parecido com o resultado seguinte, dentro da porção de antifalsificação:

Output
. . . block drop in quick on ! vtnet0 inet from your_server_ip/20 to any block drop in quick on ! vtnet0 inet from network_address/16 to any block drop in quick inet from your_server_ip to any block drop in quick inet from network_address to any block drop in quick on vtnet0 inet6 from your_IPv6_address to any . . .

Sua regra de antifalsificação descobriu que faz parte da rede your_server_ip/20. Ela também detectou que (para este exemplo do tutorial) o servidor faz parte de uma rede network_address/16 e possui um endereço IPv6 adicional. A antifalsificação bloqueia todas estas redes de comunicação com o sistema, a menos que o tráfego delas passe pela interface vtnet0.

Sua regra de antifalsificação é a última adição ao seu conjunto de regras base. No próximo passo, você iniciará essas alterações e executará alguns testes.

Passo 4 — Testando seu conjunto de regras base

Neste passo, você revisará e testará seu conjunto de regras base para garantir que tudo esteja funcionando corretamente. É melhor evitar implementar muitas regras de uma só vez, sem antes testá-las. A melhor coisa a se fazer é começar pelo essencial, expandir de maneira incremental e voltar a trabalhar nisso à medida que você faz alterações na configuração.

Aqui está seu conjunto de regras base completo:

Base Ruleset /etc/pf.conf
vtnet0 = "vtnet0"
icmp_types = "{ echoreq unreach }"
table <bruteforce> persist
table <rfc6890> { 0.0.0.0/8 10.0.0.0/8 100.64.0.0/10 127.0.0.0/8 169.254.0.0/16          \
                  172.16.0.0/12 192.0.0.0/24 192.0.0.0/29 192.0.2.0/24 192.88.99.0/24    \
                  192.168.0.0/16 198.18.0.0/15 198.51.100.0/24 203.0.113.0/24            \
                  240.0.0.0/4 255.255.255.255/32 }

set skip on lo0
scrub in all fragment reassemble max-mss 1440
antispoof quick for $vtnet0
block in quick on $vtnet0 from <rfc6890>
block return out quick on egress to <rfc6890>
block all
pass in on $vtnet0 proto tcp to port { 22 } \
    keep state (max-src-conn 15, max-src-conn-rate 3/1, \
        overload <bruteforce> flush global)
pass out proto { tcp udp } to port { 22 53 80 123 443 }
pass inet proto icmp icmp-type $icmp_types

Confirme se o arquivo /etc/pf.conf é idêntico ao conjunto de regras base completo antes de prosseguir. Então, salve e saia do arquivo.

Seu conjunto de regras base completo fornece a você:

  • Uma coleção de macros, que pode definir serviços e dispositivos essenciais.
  • Políticas de higiene de rede direcionadas à fragmentação de pacote e endereços IP inconsistentes.
  • Uma estrutura de filtragem default deny, que bloqueia tudo e permite somente o que você especificar.
  • Acesso SSH de entrada com limites no número de conexões simultâneas que podem ser feitas por um host.
  • Políticas de tráfego de saída, que dão acesso a alguns serviços cruciais da Internet.
  • Políticas de ICMP, que fornecem acesso ao utilitário ping e ao MTU path discovery.

Execute o seguinte comando pfctl para fazer uma simulação:

  • sudo pfctl -nf /etc/pf.conf

Utilize os sinalizadores -nf, que mandam o pfctl executar o conjunto de regras sem carregá-lo. Este processo apontará erros, caso eles existam.

Agora, sem erros encontrados, carregue o conjunto de regras:

  • sudo pfctl -f /etc/pf.conf

Caso não haja erros, significa que seu conjunto de regras base está ativo e funcionando corretamente. Como anteriormente no tutorial, você executará alguns testes em seu conjunto de regras.

Primeiro, teste a conectividade da Internet e do serviço DNS:

  • ping -c 3 google.com

Você verá o seguinte resultado:

Output
PING google.com (172.217.0.46): 56 data bytes 64 bytes from 172.217.0.46: icmp_seq=0 ttl=56 time=2.088 ms 64 bytes from 172.217.0.46: icmp_seq=1 ttl=56 time=1.469 ms 64 bytes from 172.217.0.46: icmp_seq=2 ttl=56 time=1.466 ms --- google.com ping statistics --- 3 packets transmitted, 3 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 1.466/1.674/2.088/0.293 ms

Em seguida, verifique se você tem acesso ao repositório pkgs:

  • sudo pkg upgrade

Novamente, atualize os pacotes caso seja necessário.

Por fim, reinicie seu servidor:

  • sudo reboot

Espere alguns minutos para seu servidor reinicializar. Você completou e implementou seu conjunto de regras base, que é um passo importante para você. Agora tudo está pronto para explorar alguns recursos avançados do PF. No próximo passo, você aprenderá a prevenir ataques de força bruta.

Passo 5 — Gerenciando sua tabela de sobrecarga

Ao longo do tempo, a tabela de sobrecarga <bruteforce> ficará cheia de endereços IP mal-intencionados e precisará de limpezas periódicas. É pouco provável que um invasor continuará utilizando o mesmo endereço IP. Assim, é contraintuitivo armazená-los em uma tabela de sobrecarga por muito tempo.

Você usará o pfctl para limpar manualmente os endereços IP que foram armazenados na tabela de sobrecarga por 48 horas ou mais, com o seguinte comando:

  • sudo pfctl -t bruteforce -T expire 172800

Você verá um resultado semelhante a:

Output
0/0 addresses expired.

Passe o sinalizador -t bruteforce, que significa table bruteforce, e o sinalizador -T, que permite que você execute vários comandos integrados. Neste caso, execute o comando expire para limpar todas as entradas da t- bruteforce com um valor de tempo representado em segundos. Como você está trabalhando em um servidor novo, é provável que não exista endereço IP na tabela de sobrecarga ainda.

Esta regra funciona para correções rápidas, mas para uma solução mais robusta, seria uma melhor opção automatizar o processo com o cron, o agendador de tarefas do FreeBSD. Em vez disso, vamos criar um script do shell que execute esta sequência de comandos.

Crie um arquivo de script de shell no diretório /usr/local/bin:

  • sudo vi /usr/local/bin/clear_overload.sh

Adicione o conteúdo a seguir ao seu script do shell:

/usr/local/bin/clear_overload.sh
#!/bin/sh

pfctl -t bruteforce -T expire 172800

Crie o arquivo executável com o seguinte comando:

  • sudo chmod 755 /usr/local/bin/clear_overload.sh

Em seguida, crie um cron job. Essas são tarefas que serão executadas automaticamente, de acordo com o tempo que você especificar. Elas são geralmente utilizadas para backups, ou qualquer outro processo que necessite de ser executado em um mesmo horário, todo dia. Crie tarefas do cron com arquivos do crontab. Consulte as páginas do manual para aprender mais a respeito do cron(8) e do crontab(5).

Crie um arquivo crontab do usuário root com o seguinte comando:

  • sudo crontab -e

Agora, adicione o conteúdo a seguir ao arquivo crontab:

crontab
# minute    hour    mday    month   wday    command

  *             0     *       *     *     /usr/local/bin/clear_overload.sh

Salve e saia do arquivo.

Nota: se perceber que o alinhamento não está correto ao adicionar o conteúdo, alinhe cada valor ao seu campo de entrada correspondente da tabela para facilitar a leitura.

Este cron job executa o script clear_overload.sh todo dia à meia noite, removendo endereços IP com 48 horas da overload table <bruteforce>. Em seguida, adicione âncoras ao seu conjunto de regras.

Passo 6 — Introduzindo âncoras em seus conjuntos de regras

Neste passo, você introduzirá as anchors, que são utilizadas para fornecer regras para o conjunto de regras principal, seja manualmente ou de um arquivo de texto externo. As âncoras podem conter trechos de regra, tabelas e até mesmo outras âncoras, conhecidas como nested anchors (âncoras aninhadas). Vamos demonstrar como as âncoras funcionam, adicionando uma tabela a um arquivo externo e fornecendo-o ao seu conjunto de regras base. Sua tabela incluirá um grupo de hosts internos, e você deve evitar que estes hosts se conectem ao mundo exterior.

Crie um arquivo chamado /etc/blocked-hosts-anchor:

  • sudo vi /etc/blocked-hosts-anchor

Adicione o conteúdo a seguir ao arquivo:

/etc/blocked-hosts-anchor
table <blocked-hosts> { 192.168.47.1 192.168.47.2 192.168.47.3 }

block return out quick on egress from <blocked-hosts>

Salve e saia do arquivo.

Estas regras declaram e definem a tabela <blocked-hosts> e, em seguida, impedem todo endereço IP presente na tabela <blocked-hosts> de acessar serviços do mundo exterior. Use a palavra-chave do egress como um método favorito de encontrar a rota padrão ou a saída para a Internet.

Você ainda precisa declarar a âncora em seu arquivo /etc/pf.conf:

  • sudo vi /etc/pf.conf

Agora, adicione as seguintes regras de âncora após a regra block all:

/etc/pf.conf
. . .
block all
anchor blocked_hosts
load anchor blocked_hosts from "/etc/blocked-hosts-anchor"
. . .

Salve e saia do arquivo.

Estas regras declaram os blocked_hosts e carregam as regras de âncora em seu conjunto de regras principal do arquivo /etc/blocked-hosts-anchor.

Agora, inicie essas alterações recarregando seu conjunto de regras com o pfctl:

  • sudo pfctl -f /etc/pf.conf

Caso não ocorram erros, não existem erros em seu conjunto de regras e as alterações estão ativas.

Utilize o pfctl para verificar que sua âncora está funcionando:

  • sudo pfctl -s Anchors

O sinalizador -s Anchors significa “mostrar âncoras”. Você verá o seguinte resultado:

Output
blocked_hosts

O utilitário pfctl também pode analisar as regras específicas de sua âncora com os sinalizadores -a e -s:

  • sudo pfctl -a blocked_hosts -s rules

Você verá o seguinte resultado:

Output
block return out quick on egress from <blocked-hosts> to any

Outra característica das âncoras é que elas permitem que você adicione regras sob demanda sem a necessidade de recarregar o conjunto de regras. Esta regra pode ser útil na realização de testes, correções rápidas, emergências e assim por diante. Por exemplo, se um host interno estiver agindo de modo estranho e você quiser bloqueá-lo de fazer conexões externas, coloque uma âncora que permita que você intervenha rapidamente a partir da linha de comando.

Vamos abrir o /etc/pf.conf e adicionar outra âncora:

  • sudo vi /etc/pf.conf

Você nomeará a âncora de rogue_hosts e a colocará na regra block all:

/etc/pf.conf
. . .
block all
anchor rogue_hosts
. . .

Salve e saia do arquivo.

Para iniciar estas mudanças, recarregue o conjunto de regras com o pfctl:

  • sudo pfctl -f /etc/pf.conf

Novamente, utilize o pfctl para verificar se a âncora está funcionando:

  • sudo pfctl -s Anchors

Isso gerará o seguinte resultado:

Output
blocked_hosts rogue_hosts

Agora que a âncora está funcionando, você pode adicionar regras a ela a qualquer momento. Teste isso, adicionando a seguinte regra:

  • sudo sh -c 'echo "block return out quick on egress from 192.168.47.4" | pfctl -a rogue_hosts -f -'

Esta regra invoca o comando echo e seu conteúdo string, que é então redirecionado para o utilitário pfctl com o símbolo |, onde será processado em uma regra de âncora. Abra outra sessão shell com o comando sh -c. Isto é necessário porque você estabelece um pipe entre dois processos, mas são necessários privilégios sudo para completar toda a sequência de comandos. Há várias maneiras de resolver isso; abra um processo shell adicional com privilégios sudo usando sudo sh -c.

Utilize o pfctl novamente para verificar se essas regras estão ativas:

  • sudo pfctl -a rogue_hosts -s rules

Isso gerará o seguinte resultado:

Output
block return out quick on egress inet from 192.168.47.4 to any

O uso de âncoras é completamente ocasional e frequentemente subjetivo. Como qualquer outro recurso, o uso de âncoras tem aspectos positivos e negativos. Alguns aplicativos, como o blacklistd, foram projetados para interagir com âncoras. Em seguida, você deve se concentrar em iniciar seu acesso com o PF, que é um aspecto crucial da segurança de rede. Seu firewall não é útil se você não puder ver o que ele está fazendo.

Passo 7 — Acessando a atividade do seu firewall

Neste passo, você trabalhará com o acesso ao PF, que é gerenciado por uma pseudointerface chamada pflog. O acesso é habilitado na inicialização, ao adicionar pflog_enabled=YES ao arquivo /etc/rc.conf, feito no Passo 2. Isso habilita o daemon pflogd, que abre uma interface chamada pflog0 e grava registros em formato binário em um arquivo chamado /var/log/pflog. Os registros podem ser analisados em tempo real pela interface, ou lidos no arquivo /var/log/pflog, com o utilitário tcpdump(8).

Primeiro, acesse alguns registros do arquivo /var/log/pflog:

  • sudo tcpdump -ner /var/log/pflog

Utilize os sinalizadores -ner, que formatam a saída para facilitar a leitura, e especifique um arquivo para leitura, que, neste caso, é o /var/log/pflog.

Você verá o seguinte resultado:

Output
reading from file /var/log/pflog, link-type PFLOG (OpenBSD pflog file)

Nestes estágios iniciais, pode não haver dados no arquivo /var/log/pflog. Em um curto período de tempo, o arquivo de registro começará a crescer.

Você também pode visualizar os registros em tempo real pela interface pflog0, usando o seguinte comando:

  • sudo tcpdump -nei pflog0

Utilize os sinalizadores -nei, que também formatam a saída para leitura, mas desta vez, especifique uma interface, que, neste caso, é o pflog0.

Você verá o seguinte resultado:

Output
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on pflog0, link-type PFLOG (OpenBSD pflog file), capture size 262144 bytes

Agora, você verá as conexões em tempo real. Caso seja possível, envie um ping ao seu servidor de uma máquina remota e veja as conexões acontecendo. O servidor permanecerá neste estado até que você saia dele.

Para sair deste estado e voltar para a linha de comando, pressione CTRL + Z.

Existe uma grande quantidade de informações na Internet a respeito do tcpdump(8), incluindo o website oficial.

Acessando arquivos de registro com o pftop

O utilitário pftop é uma ferramenta para visualizar, de maneira rápida, a atividade do firewall em tempo real. Seu nome é influenciado pelo famoso utilitário do Unix, o top.

Para usá-lo, você precisa instalar o pacote pftop:

  • sudo pkg install pftop

Agora, execute o binário pftop:

  • sudo pftop

Isso gerará o seguinte resultado (seus IPs serão diferentes):

Output
PR DIR SRC DEST STATE AGE EXP PKTS BYTES tcp In 251.155.237.90:27537 157.225.173.58:22 ESTABLISHED:ESTABLISHED 00:12:35 23:59:55 1890 265K tcp In 222.186.42.15:25884 157.225.173.58:22 TIME_WAIT:TIME_WAIT 00:01:25 00:00:06 22 3801 udp Out 157.245.171.59:4699 67.203.62.5:53 MULTIPLE:SINGLE 00:00:14 00:00:16 2 227

Criando interfaces de registros adicionais

Assim como em qualquer outra interface, várias interfaces de registro podem ser criadas e nomeadas com um arquivo /etc/hostname. Isto é útil para fins de organização, por exemplo, se quiser registrar certos tipos de atividade separadamente.

Crie uma interface de registro adicional chamada pflog1:

  • sudo vi /etc/hostname.pflog1

Adicione o conteúdo a seguir ao arquivo /etc/hostname.pflog1:

/etc/hostname.pflog1
up

Agora, habilite o dispositivo no momento da inicialização em seu arquivo /etc/rc.conf:

  • sudo sysrc pflog1_enable="YES"

Com isso, você pode monitorar e registrar a atividade do firewall. Isto permite que você veja quem está fazendo as conexões em seu servidor e os tipos de conexões.

Ao longo deste tutorial, você incorporou alguns conceitos avançados em seu conjunto de regras PF. Só é necessário implementar recursos avançados se precisar deles. Dito isto, no próximo passo, você reverterá o conjunto de regras base.

Passo 8 — Revertendo seu conjunto de regras base

Nesta última seção, você reverterá as alterações feitas em seu conjunto de regras base. Este é um passo rápido, que levará a funcionalidade de volta a seu estado minimalista.

Abra o conjunto de regras base com o seguinte comando:

  • sudo vi /etc/pf.conf

Exclua o conjunto de regras atual em seu arquivo e substitua-o pelo conjunto de regras base seguinte:

/etc/pf.conf
vtnet0 = "vtnet0"
icmp_types = "{ echoreq unreach }"
table <bruteforce> persist
table <rfc6890> { 0.0.0.0/8 10.0.0.0/8 100.64.0.0/10 127.0.0.0/8 169.254.0.0/16          \
                  172.16.0.0/12 192.0.0.0/24 192.0.0.0/29 192.0.2.0/24 192.88.99.0/24    \
                  192.168.0.0/16 198.18.0.0/15 198.51.100.0/24 203.0.113.0/24            \
                  240.0.0.0/4 255.255.255.255/32 }

set skip on lo0
scrub in all fragment reassemble max-mss 1440
antispoof quick for $vtnet0
block in quick on $vtnet0 from <rfc6890>
block return out quick on egress to <rfc6890>
block all
pass in on $vtnet0 proto tcp to port { 22 } \
    keep state (max-src-conn 15, max-src-conn-rate 3/1, \
        overload <bruteforce> flush global)
pass out proto { tcp udp } to port { 22 53 80 123 443 }
pass inet proto icmp icmp-type $icmp_types

Salve e saia do arquivo.

Recarregue o conjunto de regras:

  • sudo pfctl -f /etc/pf.conf

Se não houver erros no comando, não existirão erros em seu conjunto de regras, e seu firewall funcionará corretamente.

Também é necessário desativar a interface pflog1, que você criou. Como você ainda não sabe se precisará dela, desative o pflog1 com o utilitário sysrc:

  • sudo sysrc pflog1_enable="NO"

Agora, remova o arquivo /etc/hostname.pflog1 do diretório /etc:

  • sudo rm /etc/hostname.pflog1

Antes de sair, reinicie o servidor mais uma vez para garantir que todas as mudanças estão ativas e persistentes:

  • sudo reboot

Espere alguns minutos antes de fazer o login em seu servidor.

De maneira opcional, se quiser implementar o PF com um servidor Web, o seguinte conjunto de regras será apropriado para este cenário. Este conjunto de regras é um ponto de partida suficiente para a maioria dos aplicativos Web.

Simple Web Server Ruleset
vtnet0 = "vtnet0"
icmp_types = "{ echoreq unreach }"
table <bruteforce> persist
table <webcrawlers> persist
table <rfc6890> { 0.0.0.0/8 10.0.0.0/8 100.64.0.0/10 127.0.0.0/8 169.254.0.0/16          \
                  172.16.0.0/12 192.0.0.0/24 192.0.0.0/29 192.0.2.0/24 192.88.99.0/24    \
                  192.168.0.0/16 198.18.0.0/15 198.51.100.0/24 203.0.113.0/24            \
                  240.0.0.0/4 255.255.255.255/32 }

set skip on lo0
scrub in all fragment reassemble max-mss 1440
antispoof quick for $vtnet0
block in quick on $vtnet0 from <rfc6890>
block return out quick on egress to <rfc6890>
block all
pass in on $vtnet0 proto tcp to port { 22 } \
    keep state (max-src-conn 15, max-src-conn-rate 3/1, \
        overload <bruteforce> flush global)
pass in on $vtnet0 proto tcp to port { 80 443 } \
    keep state (max-src-conn 45, max-src-conn-rate 9/1, \
        overload <webcrawlers> flush global)
pass out proto { tcp udp } to port { 22 53 80 123 443 }
pass inet proto icmp icmp-type $icmp_types

Isto cria uma tabela de sobrecarga chamada <webcrawlers>, que tem uma política de sobrecarga mais liberal que sua porta SSH, baseada nos valores do max-src-conn 45 e max-src-conn-rate. Isto acontece devido ao fato de que nem todas as sobrecargas são oriundas de atores proibidos. Elas também podem ser originárias de netbots não maliciosos, logo, evite o uso de medidas de segurança em excesso nas portas 80 e 443. Caso decida implementar o conjunto de regras do servidor Web, será necessário adicionar a tabela <webcrawlers> ao /etc/pf.conf e limpar os IPS da tabela periodicamente. Consulte o Passo 5 para isso.

Conclusão

Neste tutorial, você configurou o PF no FreeBSD 12.1. Agora, você tem um conjunto de regras base, que pode servir como um ponto de partida para todos os seus projetos do FreeBSD. Para obter mais informações sobre o PF, consulte as páginas do manual pf.conf(5).

Visite nossa página de tópicos do FreeBSD para obter mais tutoriais e perguntas e respostas.

Creative Commons License