firewall

Devido a indisponibilidade de tempo livre, estou com uma pequena dificuldade para incluir artigos que cubram conceitos fundamentais sobre o netfilter ou firewall em geral. Mas, em breve, incluirei alguns artigos mais conceituais também (são importantes). Aguardem!

No momento, estou compartilhando dicas mais pontuais e práticas. Hoje, abordarei algumas técnicas para controle de acesso a sites. Demonstrarei algumas “brincadeiras” mais conhecidas e outras que são pouco documentadas, demonstrando o quão flexível uma solução de código aberto pode ser.

Você perceberá que o netfilter permite muito mais que uma simples filtragem de sockets.

A partir de um firewall Linux, é possível limitar o acesso a sites como youtube e facebook com grande facilidade. No entanto, este controle pode ser implementado de diferentes maneiras.

Pessoalmente, acredito que o controle estabelecido por meio de um Proxy, como o Squid, é a forma mais flexível, eficiente e ideal.

1. Alguns administradores, menos experimentados, preferem escrever filtros diretos (via iptables).

Por exemplo:

iptables -A FORWARD -d www.facebook.com -j DROP
iptables -A FORWARD -d www.youtube.com -j DROP

Infelizmente, a regra demonstrada é extremamente ineficiente e deve ser evitada, pois o filtro não será processado da maneira que faz parecer.

Internamente, o filtro será aplicado por endereço IP e não por nome FQDN. Antes da regra ser carregada, ocorre uma tradução de nome e o sistema armazena o endereço IP obtido “no instante da consulta“. Dependendo da resolução de DNS, o filtro pode funcionar apenas por alguns dias, horas ou variar de acordo com o DNS configurado nas estações. Em alguns casos, para manter as regras atualizadas, seria necessário recarregá-las periodicamente (sem garantias).

Confiram o resultado, que acabo de simular, para o youtube:

~# iptables -A FORWARD -d www.youtube.com -j DROP
~# iptables -nL FORWARD -v
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DROP       all  --  *      *       0.0.0.0/0            189.7.75.19         
    0     0 DROP       all  --  *      *       0.0.0.0/0            189.7.75.59         
    0     0 DROP       all  --  *      *       0.0.0.0/0            189.7.75.57         
    0     0 DROP       all  --  *      *       0.0.0.0/0            189.7.75.27         
    0     0 DROP       all  --  *      *       0.0.0.0/0            189.7.75.44         
    0     0 DROP       all  --  *      *       0.0.0.0/0            189.7.75.15         
    0     0 DROP       all  --  *      *       0.0.0.0/0            189.7.75.23         
    0     0 DROP       all  --  *      *       0.0.0.0/0            189.7.75.38         
    0     0 DROP       all  --  *      *       0.0.0.0/0            189.7.75.49         
    0     0 DROP       all  --  *      *       0.0.0.0/0            189.7.75.53         
    0     0 DROP       all  --  *      *       0.0.0.0/0            189.7.75.29         
    0     0 DROP       all  --  *      *       0.0.0.0/0            189.7.75.42         
    0     0 DROP       all  --  *      *       0.0.0.0/0            189.7.75.45         
    0     0 DROP       all  --  *      *       0.0.0.0/0            189.7.75.34         
    0     0 DROP       all  --  *      *       0.0.0.0/0            189.7.75.30         

A partir de um único comando gerei 15 regras (internamente).

Há outros inconvenientes. Com a ampla adoção da computação distribuída em nuvem, o problema é ainda maior. Dependendo do IP traduzido, o bloqueio pode atingir diferentes sites. E, caso ocorram instabilidades na tradução, o tempo de processamento das regras será comprometido. Em minha opinião, este tipo de filtro deve ser evitado ao máximo.

2. Ainda procurando fugir da instalação de um serviço Proxy, alguns administradores, optam pela filtragem de string diretamente no payload.

Trata-se de uma opção interessante que “funciona” realmente. Mas, o resultado é bastante questionável, podendo implicar em diferentes problemas também.

Confiram o seguinte exemplo:

iptables -A FORWARD -m string --string "facebook.com" --algo bm -j DROP
iptables -A FORWARD -m string --string "youtube.com" --algo bm -j DROP

A extensão “string” permite a filtragem de “palavras” no payload de qualquer pacote. A busca destas palavras pode ser feita através do algoritmo “bm” (Boyers-Moore) ou “kmp” (Knuth-Morris-Pratt).

O processamento do algoritmo bm é considerado mais rápido e, com isto, costuma ser o mais utilizado. Para diminuir os ciclos de CPU, é possível delimitar a “profundidade” de inspeção especificando limites de offset (–from e –to) – no link da nintechnet, exibido abaixo, há exemplos mais avançados.

O filtro demonstrado “funciona”, mas poderá causar instabilidades e problemas de performance. Não imagine que o custo de CPU seja o maior problema. Não é. Muitos portais incluem, em seu código, plugins para integração com redes sociais ou vídeos do youtube. Caso o processamento da página seja síncrono, uma regra como esta impedirá o carregamento do código até o final. Desta forma, a experiência do usuário será de um acesso instável ou extremamente lento. Há algum tempo atrás, você perceberia isto ao acessar o site do Banco do Brasil, por exemplo.

Por incrível que pareça, se eu incluir estas regras (para efeito de testes), na cadeia OUTPUT de minha estação de trabalho, não conseguirei submeter esta postagem. Percebam que não é tão simples.

Isto não quer dizer que você não possa trabalhar com a extensão string, apenas tenha compreensão do efeito.

Suponhamos que a navegação de sua rede (porta tcp/80 ou 443) seja liberada apenas para um servidor Proxy, que limita o acesso a redes sociais, como o facebook (por exemplo). No entanto, uma estação da rede está com o cliente do facebook instalado e está causando um flood de conexões – como se a aplicação estivesse em um loop até conseguir conexão.

O exemplo é real, e precisei tratar há pouco tempo (gerava centenas de conexões em curto espaço de tempo).

Neste caso, poderíamos limitar a frequência de conexões escrevendo uma regra assim:

# Limites de acesso ao facebook por ip de origem (clientes) e ip e porta de destino (proxy)
/sbin/iptables -t filter -N facelimit 2>/dev/null
/sbin/iptables -t filter -A facelimit -p tcp -m hashlimit --hashlimit-htable-max 30000 --hashlimit-mode srcip,dstip,dstport --hashlimit 60/m --hashlimit-burst 240 --hashlimit-name facelimit1 -j RETURN
/sbin/iptables -t filter -A facelimit -m limit --limit 3/s --limit-burst 3 -j LOG --log-level info --log-prefix "DROP profile facelimit "
/sbin/iptables -t filter -A facelimit -j DROP

# Limites por string
/sbin/iptables -t filter -N DropStr 2>/dev/null
/sbin/iptables -t filter -A DropStr   -p tcp -m string --string "realtime.services.disqus.com" --algo bm -j DROP
/sbin/iptables -t filter -A DropStr   -p tcp -m string --string "update2/octoshapeold/win32" --algo bm -j DROP
/sbin/iptables -t filter -A DropStr   -p tcp -m string --string "octoshape.net" --algo bm -j DROP
/sbin/iptables -t filter -A DropStr   -p tcp -m string --string "storage.conduit.com" --algo bm -j DROP
/sbin/iptables -t filter -A DropStr   -p tcp -m string --string ".facebook.com" --algo bm -j facelimit

# Aplicando a filtragem por string
/sbin/iptables -A FORWARD -d [ip_do_proxy] -p tcp --dport [porta_do_proxy] ! --syn -j DropStr

A regra anterior amenizou os efeitos do flood descrito. Como o netfilter oferece uma flexibilidade de configuração extensa, podemos, ainda, limitar o número de pacotes que serão processados pela cadeia DropStr. Isto desonera a CPU de processamento desnecessário durante o download de arquivos.

É possível otimizar o processamento destas regras limitando o número de pacotes através da extensão connbytes:

/sbin/iptables -I DropStr -p tcp -m connbytes --connbytes 18 --connbytes-dir both --connbytes-mode packets -j RETURN

Confiram um exemplo ainda mais avançado:
http://blog.nintechnet.com/how-to-block-w00tw00t-at-isc-sans-dfind-and-other-web-vulnerability-scanners/

Conforme o nosso domínio sobre as extensões ou possibilidades de configuração aumenta, fica mais fácil criar uma combinação de regras que permita desenvolver controles disponíveis apenas na camada de aplicação. De acordo com a lógica defendida no exemplo acima, desenvolvi uma configuração de firewall capaz de gerenciar uma blacklist dinâmica, ainda mais flexível. Não abordarei agora porque fugiria do escopo principal.

3. Outra alternativa, menos conhecida, é a filtragem de consultas de DNS.

iptables -A FORWARD -p udp --dport 53 -m string --hex-string "|03|www|08|facebook|03|com" --algo bm -j DROP
iptables -A FORWARD -p udp --dport 53 -m string --hex-string "|03|www|07|youtube|03|com" --algo bm -j DROP

Caso o firewall seja o único gateway da rede, é possível impedir qualquer tradução de DNS que contenha a string www.facebook.com ou www.youtube.com. No caso da resolução de DNS, antes de cada bloco do nome FQDN, é preciso identificar o número de caracteres em hexadecimal (em ||).

É uma alternativa interessante, mas, de uma maneira geral, é pouco eficiente. O que acontecerá se você souber ou anotar os IPs e cadastrar manualmente no arquivo hosts? Terá acesso aos sites facilmente. É evidente o filtro será mandatório se for aplicado para controlar as requisições originadas pelo Proxy, sem permitir qualquer conexão destinada diretamente a porta 80 ou 443.

4. Caso exista um serviço de IPS disponível, como Snort ou Suricata, podemos utilizá-lo para identificar e bloquear qualquer violação das políticas de acesso.

drop tcp any any -> any any (msg:"DROP Facebook"; content:"facebook.com"; http_header; nocase; classtype:policy-violation; sid:90000100; rev:1)

Perceba que existe uma ampla gama de alternativas. O meu objetivo foi demonstrar a flexibilidade de filtro e algumas possibilidades de configuração, bem como as consequências de sua adoção.

Se você deseja adotar um filtro de acesso, para determinados sites, de forma eficiente, configure um servidor Proxy. As alternativas demonstradas, como o filtro com a cadeia DropStr, são apenas complementares.