[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 from any to any 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 from any to any 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.
A partir do OpenBSD 4.1, todas as regras de filtragem criam automaticamente uma entrada de estado quando um pacote corresponde à regra. Em versões antigas do OpenBSD, a regra de filtragem tinha que usar explicitamente a opção keep state.
Exemplo de uso no OpenBSD 4.1 e versões recentes:
pass out on fxp0 proto tcp from any to any
Exemplo de uso no OpenBSD 4.0 e versões anteriores:
pass out on fxp0 proto tcp from any to any keep state
Isso permite qualquer tráfego TCP saindo pela interface fxp0, bem como o tráfego retornando em resposta ao firewall. Além do recurso de manter estado ser uma excelente característica, seu uso ainda melhora o desempenho do firewall, pois pesquisas na tabela de estados são muito mais rápidas do que passar o pacote por todas as 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. Desde o OpenBSD 3.5, a opção modulate state pode ser usada também em regras que especifiquem protocolos diferentes do TCP.
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.
Perceba que para regras nat, binat e rdr é implícita a criação de estados para conexões válidas desde que os pacotes tenham passado pelo conjunto de regras de filtragem.
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
A regra acima autoriza tráfego TCP com o sinalizador SYN definido, mas verifica somente os sinalizadores SYN e ACK. Um pacote com os sinalizadores SYN e ECE corresponderia à regra acima, enquanto um pacote com SYN e ACK ou somente ACK não corresponderia.
No OpenBSD 4.1 e versões recentes, os sinalizadores aplicados por padrão nas regras TCP são flags S/SA. Combinando com o padrão do OpenBSD 4.1 de "keep state" (manter o estado) nas regras de filtragem, estas duas regras se tornaram equivalentes:
pass out on fxp0 proto tcp all flags S/SA keep state
pass out on fxp0 proto tcp all
Cada regra corresponde à pacotes TCP com o sinalizador SYN marcado e o sinalizador ACK desmarcado, e cada uma cria um estado para os pacotes que corresponderam. Os sinalizadores padrão podem ser sobrescritos usando a opção flags conforme descrito acima.
No OpenBSD 4.0 e versões anteriores, não existiam sinalizadores padrão aplicados a nenhuma regra de filtragem. Cada regra tinha que especificar qual(is) sinalizador(es) corresponder, e também tinha que explicitar o uso da opção keep state.
pass out on fxp0 proto tcp all flags S/SA keep state
Deve-se tomar cuidado ao usar sinalizadores -- entenda o que você está fazendo e o porquê, e 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". Essa regra deve ficar assim:
. . . flags S/FSRPAUEW má ideia!!
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
Além de ser prático e seguro, também não é necessário verificar os sinalizadores FIN e RST caso o tráfego passe antes por regras de scrub. No processo de normalização o PF descarta quaisquer pacotes que cheguem com combinações de sinalizadores TCP inválidas (como SYN e RST) e normaliza combinações ambíguas em potencial (como SYN e 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. O benefício desse procedimento é que nenhum pacote é enviado ao servidor antes do cliente completar o aperto de mão. Isso evita que ataques de inundação de pacotes TCP SYN falsificados atinjam o servidor porque uma conexão falsificada não conseguirá completar o aperto de mão.
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 from any to $web_server port www \
flags S/SA 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.
A partir do OpenBSD 4.0, 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 from any os OpenBSD keep state
block in on $ext_if from any os "Windows 2000"
block in on $ext_if from any os "Linux 2.4 ts"
block in on $ext_if 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 to any
pass out on $int_if from any 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. Usa o tcp syn proxy nas conexões.
# Os sinalizadores "S/SA" padrão serão aplicados automaticamente na
# regra pelo PF.
pass in log on $ext_if proto tcp from any to ! <firewall> \
port ssh synproxy state
|
[Anterior: Tabelas] [Conteúdo] [Próximo: Tradução do Endereço de Rede (NAT)]