[Anterior: Tabelas] [Conteúdo] [Próximo: Tradução do Endereço de Rede (NAT)]
Regras de filtragem especificam o critério em que o pacote deve se enquadrar e a ação resultante que é tomada quando o pacote corresponde à regra, que pode ser o bloqueio ou a liberação. As regras de filtragem são avaliadas em sequência, da primeira até a última. A menos que o pacote corresponda a uma regra contendo a palavra-chave quick, ele é avaliado por todas as regras de filtragem antes da ação final ser tomada. A última regra a corresponder é a "vencedora" e dita qual ação tomar. Existe um pass all implícito no início de um conjunto de regras de filtragem, que significa que caso o pacote não corresponda a nenhuma regra a ação resultante será pass.
ação [direção] [log] [quick] [on interface] [fam_de_end] [proto protocolo] \
[from end_de_or [port porta_de_or]] [to end_de_dest [port porta_de_dest]] \
[flags sinalizadores_tcp] [estado]
Para criar uma política de filtragem de negar por padrão, as primeiras duas regras de filtragem devem ser:
block in all
block out all
Isso bloqueia todo o tráfego em todas interfaces em qualquer direção, de qualquer lugar para qualquer lugar.
Alguns exemplos:
# Libera o tráfego entrando na interface dc0, vindo da rede local
# 192.168.0.0/24 e indo para a máquina OpenBSD com o endereço IP
# 192.168.0.1. Também permite o tráfego de retorno saindo da 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
# Libera o tráfego TCP chegando em fxp0 e indo para o servidor Web
# em execução na máquina OpenBSD. O nome da interface, fxp0, é usado
# como endereço de destino, de modo que aqueles pacotes somente
# correspondam à regra se eles têm como destino a máquina OpenBSD.
pass in on fxp0 proto tcp from any to fxp0 port www
Errado:
block in on fxp0 proto tcp to port ssh
pass in all
Nesse caso, a linha block será avaliada, mas jamais terá efeito algum, pois é seguida de uma linha que permite a passagem de tudo.
Melhor:
block in quick on fxp0 proto tcp to port ssh
pass in all
Essas regras são avaliadas de maneira ligeiramente diferente. Caso a linha block corresponda à regra, devido ao uso da opção quick, o pacote será bloqueado e o restante do conjunto de regras será ignorado.
Manter informações do estado das conexões traz muitas vantagens, incluindo simplicidade na configuração do conjunto de regras e melhor desempenho na filtragem de pacotes. O PF é capaz de comparar os pacotes, indo em qualquer direção, com as entradas na tabela de estados, o que significa que regras de filtragem que autorizam o tráfego de retorno não precisam ser escritas. E, como pacotes que correspondem às conexões com o estado mantido não são avaliados pelo conjunto de regras, o tempo que o PF gasta processando aqueles pacotes pode ser reduzido drasticamente.
Quando uma regra cria estado, o primeiro pacote que corresponde à regra cria um "estado" entre o transmissor e o receptor. Agora, não somente os pacotes do transmissor para o receptor correspondem à entrada na tabela e passam direto pela avaliação do conjunto de regras, mas também os pacotes de resposta do receptor para o transmissor.
Todas as regras pass automaticamente criam um registro de estado quando um pacote corresponde aquela regra. Esse comportamento pode ser explicitamente desabilitado utilizando no state.
pass out on fxp0 proto tcp from any to any
Isso permite que qualquer tráfego TCP saia pela interface fxp0, bem como o tráfego retornando em resposta ao firewall. Manter estados de conexões dão um aumento significativo na performance do seu firewall, uma vez que consultas aos registros de estados já existentes é muito mais rápido que fazer o pacote percorrer outras regras de filtragem.
A opção modulate state funciona como a keep state, exceto que ela se aplica apenas a pacotes TCP. Com modulate state, o Número de Sequência Inicial de conexões saindo do firewall é aleatório. Isso é útil para proteger conexões iniciadas por certos sistemas operacionais que não fazem um bom trabalho ao escolher ISNs. Com intuito de criar conjuntos de regras mais simples, utilizar modulate state como uma opção na regra pode ser feito para regras que não especifiquem o protocolo TCP; nesses casos o PF tratará a regra como keep state.
Para manter o estado em pacotes TCP, UDP e ICMP, e modular ISNs TCP:
pass out on fxp0 proto { tcp, udp, icmp } from any \
to any modulate state
Outra vantagem de se manter o estado é que o tráfego ICMP correspondente também passa pelo firewall. Por exemplo, se existe uma conexão TCP passando através do firewall, com o estado sendo mantido, e chega uma mensagem de congestionamento ("source-quench") ICMP referenciando esta conexão TCP, ela será correspondida à entrada apropriada na tabela de estados e passará direto pelo firewall.
O escopo de uma entrada na tabela de estados é controlado globalmente pela opção em tempo de execução state-policy e ao nível de cada regra pelas palavras-chave de opções de estado if-bound e floating. Essas palavras-chave usadas nas regras têm o mesmo efeito de quando são usadas na opção state-policy. Exemplo:
pass out on fxp0 proto { tcp, udp, icmp } from any \
to any modulate state (if-bound)
Essa regra define que para um pacote corresponder à entrada na tabela de estados, ele deve estar transitando na interface fxp0.
Opções são especificadas dentro de parêntesis e imediatamente depois de uma das palavras-chave de estado (keep state, modulate state ou synproxy state). Múltiplas opções são separadas por vírgulas. No OpenBSD 4.1 e versões recentes, a opção keep state se tornou o padrão implícito para todas as regras de filtragem. Apesar disso, quando se especifica opções de manter estado, uma das palavras-chave deve ainda ser usada antes das opções.
Uma regra de exemplo:
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)
A regra acima define o seguinte comportamento:
Um conjunto separado de restrições pode ser colocado em conexões TCP, com o estado mantido, que completaram o aperto de mão triplo ("3-way handshake").
Ambas as opções chamam automaticamente a opção source-track rule e são incompatíveis com source-track global.
Uma vez que esses limites são colocados em conexões TCP que completaram o aperto de mão triplo, ações mais agressivas podem ser tomadas em endereços IP ofensivos.
Um exemplo:
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)
Isso faz o seguinte:
Para que o PF inspecione os sinalizadores TCP durante a avaliação de uma regra, a palavra-chave flags é usada com a seguinte sintaxe:
flags a_verificar/máscara
flags any
A parte máscara diz ao PF para verificar apenas os sinalizadores indicados, e a parte a_verificar informa o(s) sinalizador(s) que deve(m) estar "ligado(s)" no cabeçalho para que o pacote corresponda à regra. O uso da palavra-chave any permite que qualquer combinação de sinalizadores esteja definida no cabeçalho.
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
Como flags S/SA é utilizado por padrão, ambas as regras são equivalentes. As duas regras acima deixam passar o tráfego TCP com a flag SYN habilitada, preocupando-se em checar apenas as flags SYN e ACK. Um pacote que tenha as flags SYN e ECE habilitadas também cairá nas regras acima, enquanto um pacote com ambas as flags habilitadas (SYN+ACK) ou apenas com a flag ACK habilitada não corresponderá a nenhuma das regras acima.
O sinalizador de flags padrão pode ser sobrescrito usando a opção flags conforme descrito anteriormente.
Deve-se tomar cuidado ao usar sinalizadores - entenda o que você está fazendo e o porquê de estar fazendo isso - tenha cuidado com conselhos dados pelos outros, pois grande parte deles são incorretos. Algumas pessoas sugerem a criação de estado "somente se o sinalizador SYN estiver marcado, e nenhum outro". Fique atento! Se seguir esse conselho, a regra ficaria assim:
. . . flags S/FSRPAUEW UMA PÉSSIMA IDÉIA!!!
A teoria é criar estado apenas no início da sessão TCP, e a sessão deve ser iniciada somente com um sinalizador SYN, e nenhum outro. O problema é que alguns lugares estão começando a usar o sinalizador ECN, e qualquer um que use ECN e tente se conectar ao seu servidor seria rejeitado por essa regra. Uma abordagem muito melhor seria não especificar sinalizador nenhum e deixar o PF aplicar os sinalizadores padrão nas suas regras. Se você realmente necessita de especificar os sinalizadores você mesmo, então esta combinação seria segura:
. . . flags S/SAFR
Embora seja prático e seguro, também é totalmente desnecessário verificar os sinalizadores FIN e RST caso o tráfego passe antes por regras de scrub. O processo de normalização adotado pelo uso de scrub fará com que o PF discarte quaisquer combinações ilegais nas flags do protocolo TCP (tais como SYN+RST) e normalizará potenciais combinações ambiguas (tais como SYN+FIN).
Normalmente quando um cliente inicia uma conexão TCP com o servidor, o PF transfere os pacotes de aperto de mão ("handshake") da forma como eles vieram. O PF, porém, possui a habilidade de fazer proxy no aperto de mão. Com o uso de proxy no aperto de mão, o próprio PF completa o aperto de mão com o cliente, inicia um aperto de mão com o servidor, e então transfere pacotes entre os dois. No caso de um ataque de flood SYN em TCP (jamais ocorrerá o "handshake" completo) os pacotes de flood nunca chegarão ao servidor protegido, mas clientes verdadeiros que tentem se conectar ao servidor terão uma conexão estabelecida normalmente. Isso minimiza o impacto de floods de SYN em TCP forjados (spoofados) destinados ao serviço protegido, tratando dos pacotes diretamente no PF. O uso rotineiro desta opção não é recomendado, pois ele quebra o comportamento esperado do protocolo TCP quando o servidor não pode processar a solicitação e quando existe algum tipo de balanceamento de carga relacionado so serviço provido por um determinado servidor.
O proxy de pacotes TCP SYN é habilitado usando as palavras-chave synproxy state em regras de filtragem. Exemplo:
pass in on $ext_if proto tcp to $web_server port www synproxy state
Aqui as conexões para o servidor Web passarão pelo proxy TCP do PF.
Pela forma como o synproxy state funciona, ele também inclui as mesmas funcionalidades de keep state e modulate state.
O proxy de pacotes SYN não funciona caso o PF esteja atuando em uma ponte (bridge(4)).
O PF oferece uma proteção contra falsificações através do uso da palavra-chave antispoof:
antispoof [log] [quick] for interface [fam_de_end]
Exemplo:
antispoof for fxp0 inet
Quando um conjunto de regras é carregado, quaisquer ocorrências da palavra-chave antispoof são expandidas em duas regras de filtragem. Assumindo que a interface fxp0 possui o endereço IP 10.0.0.1 e a máscara de sub-rede 255.255.255.0 (ou seja, /24), a regra antispoof acima expandiria para:
block in on ! fxp0 inet from 10.0.0.0/24 to any
block in inet from 10.0.0.1 to any
Essas regras fazem duas coisas:
NOTA: As regras de filtragem antispoof expandidas também bloquearão pacotes enviados pela interface de loopback para o endereço local. Recomenda-se evitar qualquer tipo de filtragem na interface de loopback, mas isso se torna uma necessidade quando usamos regras contra falsificações:
set skip on lo0
antispoof for fxp0 inet
O uso de antispoof deve ser restrito à interfaces que possuam um endereço IP. Usar antispoof em uma interface sem um endereço IP resulta em regras como:
block drop in on ! fxp0 inet all
block drop in inet all
Nessas regras existe o risco de se bloquear todo o tráfego de entrada em todas as interfaces.
O PF oferece o recurso de "Unicast Reverse Path Forwarding" (uRPF). Quando um pacote passa por uma verificação uRPF, o endereço de origem do pacote é procurado na tabela de roteamento. Se a interface de saída encontrada na entrada da tabela de roteamento é a mesma que a interface que o pacote está chegando, então a verificação uRPF libera a passagem do pacote. Se as interfaces não correspondem, então é possível que o pacote teve seu endereço de origem falsificado.
A verificação uRPF pode ser feita nos pacotes usando a palavra-chave urpf-failed nas regras de filtragem:
block in quick from urpf-failed label uRPF
Note que a verificação uRPF somente faz sentido em um ambiente onde as rotas são simétricas.
uRPF fornece a mesma funcionalidade das regras antispoof.
"Passive OS Fingerprinting" (OSFP) é um método para identificar de maneira passiva o sistema operacional de uma máquina remota com base em certas características dos pacotes TCP SYN gerados pela máquina. Essa informação pode então ser usada como critério em regras de filtragem.
O PF determina o sistema operacional remoto comparando as características do pacote TCP SYN contra um arquivo de impressões digitais, que por padrão é o /etc/pf.os. Quando o PF está habilitado, a lista atual de impressões digitais pode ser vista com o comando:
# pfctl -s osfp
Em uma regra de filtragem, a impressão digital pode ser especificada pela classe do SO, versão ou subtipo/revisão. Cada um dos itens é listado na saída do comando pfctl mostrado acima. Para especificar uma impressão digital em uma regra de filtragem, a palavra-chave os é usada:
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
A classe de sistema operacional unknown permite o enquadramento de pacotes quando a impressão digital do SO não é conhecida.
TOME NOTA:
pass in quick on fxp0 all allow-opts
ext_if = "fxp0"
int_if = "dc0"
lan_net = "192.168.0.0/24"
# Tabela contendo todos os endereços IP atribuídos ao firewall
table <firewall> const { self }
# Não filtra na interface loopback
set skip on lo0
# Faz scrub em pacotes que chegam
match in all scrub (no-df)
# Define a política "negar por padrão"
block all
# Ativa a proteção contra falsificações para todas as interfaces
block in quick from urpf-failed
# Permite conexões ssh vindas apenas da rede interna e se forem
# de um computador confiável, 192.168.0.15. "block return" faz com que
# um pacote TCP RST seja enviado para derrubar conexões bloqueadas.
# "quick" assegura que esta regra não seja invalidada por alguma
# regra "pass" abaixo.
block return in quick on $int_if proto tcp from ! 192.168.0.15 \
to $int_if port ssh
# Permite tráfego indo para e vindo da rede interna.
# Estas regras criam entradas na tabela de estados devido
# à opção padrão "keep state" que é aplicada automaticamente.
pass in on $int_if from $lan_net
pass out on $int_if to $lan_net
# Permite tráfego tcp, udp e icmp saindo pela interface externa (Internet).
# Conexões tcp serão moduladas, udp/icmp manterão o estado.
pass out on $ext_if proto { tcp udp icmp } all modulate state
# Permite conexões ssh na interface externa contanto que NÃO sejam
# destinadas ao firewall (ou seja, conexões destinadas à máquinas na
# rede local). Registra o pacote inicial para que mais tarde possamos
# saber quem tentou se conectar.
# Descomente a última parte (synproxy state) para utilizar o synproxy
# para gerenciar a conexão.
pass in log on $ext_if proto tcp to ! <firewall> \
port ssh # synproxy state
|
[Anterior: Tabelas] [Conteúdo] [Próximo: Tradução do Endereço de Rede (NAT)]