FPI - Fórum para Provedores de Internet
Gostaria de reagir a esta mensagem? Crie uma conta em poucos cliques ou inicie sessão para continuar.
FPI - Fórum para Provedores de Internet


Você não está conectado. Conecte-se ou registre-se

Escrevendo scripts de firewall Linux

3 participantes

Ir para baixo  Mensagem [Página 1 de 1]

Marcio Marques

Marcio Marques
ADMINISTRADOR FUNDADOR
ADMINISTRADOR FUNDADOR

Escrevendo scripts de firewall Linux
Por Carlos E. Morimoto
Quando falamos em "firewall", muitas vezes vem à mente um dispositivo dedicado, colocado entre o servidor (ou o switch da rede, no caso de um rede local) e a Internet. Embora firewalls dedicados sejam também bastante comuns e sejam os preferidos em grandes redes, onde o investimento é justificável, você pode obter um nível de segurança similar simplesmente usando os recursos nativos do sistema, configurando o Iptables. O firewall trabalha como um fiscal de alfandega, que analisa todos os pacotes que chegam, decidindo o que deve passar e o que deve ficar retido, através de um conjunto de regras definidas.

Um servidor destinado a compartilhar a conexão com a Internet e proteger os micros da rede local, por exemplo, usaria as regras de compartilhamento da conexão via NAT, combinadas com uma regra para permitir o acesso dos micros da rede local e regras para bloquear o tráfego proveniente da Internet. Você poderia incluir regras para abrir a porta do SSH, ou redirecionar alguma porta específica para um micro dentro da rede local rodando algum software que precisasse de portas de entrada, mas todas as demais portas ficariam fechadas.

Em um servidor de Internet, por sua vez, você não pode simplesmente bloquear todas as portas, já que, por definição, ele deve receber requisições dos clientes e disponibilizar as páginas hospedadas, entre outros recursos. Você faria então uma configuração mais cuidadosa, listando os serviços que devem ficar disponíveis, abrindo as portas referentes a eles e fechando todas as demais. As portas básicas para um servidor web, por exemplo, seriam as portas 22 (do SSH), a porta 53 (do servidor DNS) e as portas 80 e 443, usadas pelo servidor web.

Existem muitos firewalls gráficos for Linux, como o Shorewall e o Firestarter. Eles variam em nível de facilidade e recursos, oferecendo uma interface amigável e gerando as regras do Iptables de acordo com a configuração feita. Você pode escolher entre usar o programa que melhor atenda suas necessidades ou configurar diretamente o Iptables com as regras desejadas, como aprenderemos ao longo desta série de tutoriais. Nesse caso, você pode formular as regras diretamente, definindo condições onde os pacotes serão aceitos ou recusados, como em:

# iptables -A INPUT -s 192.168.1.0/255.255.255.0 -j ACCEPT

Estes comandos seguem uma sintaxe comum: tudo começa com o comando "iptables", que é o utilitário responsável por ler os parâmetros e atualizar a configuração do firewall. Em seguida, vem uma condição, indicada pela opção "-A". Neste exemplo usei "INPUT -s 192.168.1.0/255.255.255.0", que se aplica a qualquer pacote de entrada (INPUT), proveniente dos micros da rede local (192.168.1.0/255.255.255.0). Como não especifiquei o protocolo, a regra permitirá o uso dos três protocolos, ou seja, TCP, UDP e ICMP, sem restrições.

Note que aqui estou especificando uma faixa de endereços e a máscara de sub-rede (usada na rede local), fazendo com que a regra se aplique a todos os pacotes provenientes dela. No final, é preciso dizer o que fazer com os pacotes que se enquadrarem nesta condição, indicando uma ação. O "-j ACCEPT" diz que estes pacotes devem ser aceitos.

Se, por outro lado, quisesse apenas bloquear um endereço específico, usaria o parâmetro "-j REJECT", como em:

# iptables -A INPUT -s 192.168.1.23 -j REJECT

À primeira vista, configurar o firewall via linha de comando parece bastante complicado, assim como o arquivo de configuração original do Squid, com suas 3.000 e tantas linhas, mas, as coisas ficam bem mais simples se começarmos com um script simples e formos incluindo novas regras aos poucos.

A primeira coisa a ter em mente é que, assim como o Squid, o Iptables processa as regras de forma sequencial, permitindo ou recusando as conexões conforme encontra uma regra que faz referência a ela. Se uma determinada regra diz que os pacotes provenientes de um determinado endereço devem ser aceitos e outra logo depois diz que eles devem ser recusados, como neste exemplo:

# iptables -A INPUT -s 192.168.1.10 -j ACCEPT
# iptables -A INPUT -s 192.168.1.10 -j REJECT

... vale a primeira, já que ao serem autorizados por ela, os pacotes são imediatamente aceitos, sem passarem pela segunda. Ao formular as regras para seu script de firewall, você deve colocar as regras mais específicas primeiro, deixando as regras mais gerais por último. Se você quer permitir o acesso de todos os endereços provenientes da rede local, bloqueando apenas um endereço específico, você usaria:

# iptables -A INPUT -s 192.168.1.10 -j REJECT
# iptables -A INPUT -s 192.168.1.0/255.255.255.0 -j ACCEPT


Além de serem diretamente digitadas no terminal, as regras podem ser incluídas dentro de scripts, de forma que você possa ativar o firewall rapidamente e/ou configurar o sistema para carregá-lo automaticamente durante o boot. O script de firewall nada mais é do que um shell script comum, contendo os comandos que devem ser executados, um por linha. Você pode, por exemplo, criar o arquivo "/etc/init.d/firewall". Outra opção seria simplesmente adicionar os comandos no final do arquivo "/etc/rc.local", de forma que eles sejam executados durante o boot.

Este é um exemplo de mini-script de firewall que pode ser usado em um desktop que simplesmente acessa a Internet como cliente, sem rodar nenhum servidor nem compartilhar a conexão com outros micros:

#!/bin/sh
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -p tcp --syn -j DROP

A idéia aqui é que o micro possa acessar a Internet sem ficar vulnerável a acessos externos. Estes dois comandos fazem isso da forma mais simples possível.

A primeira linha orienta o firewall a deixar passar os pacotes enviados através da interface de loopback (-i lo -j ACCEPT). É importante que esta linha (ou outra com o mesmo efeito) sempre seja usada em qualquer script de firewall que termine bloqueando todas as conexões, pois, no Linux, a interface de loopback é usada para comunicação entre diversos programas. Para ter uma idéia, todos os programas gráficos a utilizam para se comunicarem com o servidor X, os programas do KDE a utilizam para trocar mensagens entre si e assim por diante. Sem esta regra, muita coisa deixa de funcionar corretamente.

Depois de abrir o firewall para as mensagens locais, usamos a segunda regra para bloquear todas as novas conexões vindas de fora. O "--syn" faz com que o firewall aplique a regra apenas para tentativas de abrir novas conexões (alguém tentando acessar o servidor SSH que você esqueceu aberto, por exemplo), sem entretanto impedir que servidores remotos respondam a conexões iniciadas por você. Isso permite que você continue navegando e acessando compartilhamentos em outros micros da rede local, com poucas limitações.

Estas duas regras podem ser usadas como base para criar um firewall de bloqueio, onde você diz as portas que gostaria de abrir e ele fecha todas as demais. Ou seja, o firewall fecha por padrão todas as portas, com exceção das que você disser explicitamente que deseja manter abertas. Isso garante uma configuração de firewall bastante segura com um mínimo de dor de cabeça.

Para testar, você pode executar o script no seu micro, ou em qualquer outro PC da rede e tentar acessá-lo via SSH (ou qualquer outro serviço ativo). Como usamos o parâmetro "DROP" na segunda regra, o PC simplesmente ignorará o chamado, fazendo com que o cliente fique um longo tempo tentando abrir a conexão, para depois exibir um erro de timeout, como em:

$ ssh 192.168.1.21

ssh: connect to host 192.168.1.21 port 22: Connection timed out

Para desativar o firewall e voltar a aceitar conexões, use o comando "iptables -F", que limpa as regras do Iptables:

# iptables -F

A partir deste script básico, você pode adicionar novas regras, abrindo portas, direcionando faixas de portas para micros da rede interna, fechando portas de saída, de forma a bloquear o uso de determinados programas e assim por diante.

Imagine que você está configurando o firewall do servidor da rede. Ele tem duas placas de rede, uma para a rede local e outra para a Internet. Você precisa que ele fique acessível sem limitações dentro da rede local, mas quer manter tudo fechado para quem vem da Internet.

Nesse caso, você poderia usar a regra que mostrei há pouco no seu script de firewall:

# Abre para uma faixa de endereços:
iptables -A INPUT -s 192.168.1.0/255.255.255.0 -j ACCEPT

O "192.168.1.0" indica a faixa de endereços da rede local. A máscara "255.255.255.0" indica que a última parte do endereço muda, ou seja, os micros da rede local usam endereços entre 192.168.1.1 e 192.168.1.254. Tudo o que vier deles é aceito.

Note que esta faixa de endereços não é roteável, ou seja, ela simplesmente não existe na Internet. Não existe a possibilidade de algum engraçadinho de outro estado tentar configurar seu micro para usar esta faixa de endereços e enganar a regra do firewall.

Como uma proteção adicional, as versões recentes do Iptables são capazes de ignorar pacotes aparentemente destinados a uma interface quando eles chegam em outra. Com duas placas, onde uma está ligada à rede local (usando a faixa 192.168.1.x) e outra à Internet, o firewall não aceitará que um pacote falseado, proveniente da Internet, com endereço de emissor "192.168.1.3" (por exemplo), seja encaminhado a um micro da rede local, pois ele sabe que pacotes com este endereço de emissor devem chegar apenas pela placa ligada à rede local.

Se o servidor possuir duas placas de rede, você poderia tornar a regra mais à prova de falhas especificando a interface de origem em vez da faixa de endereços, usando o parâmetro "-i". Com isso, o firewall é instruído a aceitar pacotes recebidos na interface de rede local, independentemente da faixa de endereços usada. Embora funcione de forma diferente, ela tem a mesma função da regra anterior. Ao usá-la, não esqueça de substituir o "eth0" pela interface de rede local, caso diferente:

# Aceita tudo na interface de rede local:
iptables -A INPUT -i eth0 -j ACCEPT

Se você é um administrador paranóico, pode também combinar as duas condições, de forma que o firewall verifique tanto a interface de origem quanto a faixa de endereços, aceitando a conexão apenas se as duas condições forem satisfeitas. Nesse caso, a regra seria:

# Verifica tanto a interface quanto a faixa de endereços de origem:
iptables -A INPUT -s 192.168.1.0/255.255.255.0 -i eth0 -j ACCEPT

O parâmetro "-s" (source), usado na regra anterior, pode também ser usado para permitir endereços ou faixas de endereços da Internet. Imagine que você precise dar acesso aos hosts de uma das filiais da empresa, onde usam um link dedicado, com uma faixa inteira de endereços, que vai do "200.220.234.1" até o "200.220.234.254". Você poderia abrir o firewall para conexões a partir da faixa "200.220.234.0" (como em: iptables -A INPUT -s 200.220.234.0/255.255.255.0 -j ACCEPT), de forma que o firewall permitisse acessos vindos de lá, mas continuar bloqueando o restante. Você pode abrir o firewall para várias faixas de endereços distintas, basta repetir a linha adicionando cada uma das faixas desejadas.

Imagine agora que este servidor foi instalado na sede de uma empresa para a qual você presta serviços. Você precisa acessá-lo de vez em quando para corrigir problemas, mas, naturalmente, vai querer fazer isso via Internet, sem precisar se deslocar até lá. Você pode configurar o firewall para abrir a porta 22, usada pelo SSH, adicionando a regra:

# Abre uma porta (inclusive para a Internet):
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

Note que esta regra abre a porta 22 para todo mundo. Lembre-se de que todo servidor disponível para a Internet é um risco potencial de segurança, por isso, só abra as portas para os servidores que você realmente for utilizar. Do ponto de vista da segurança, o ideal seria usar um par de chaves, protegidas por uma passphrase, para acessar o servidor SSH e configurá-lo para não aceitar logins com senha (apenas com chaves), como você pode ver nesta dica: http://www.hardware.com.br/dicas/ssh-login-automatico.html

Ao abrir várias portas, você pode utilizar o parâmetro "-m multiport" para especificar todas de uma vez, separadas por vírgula, sem precisar colocar uma em cada linha. Para abrir as portas 22, 80 e 443, por exemplo, você usaria a regra abaixo:

# Abre um conjunto de portas:
iptables -A INPUT -m multiport -p tcp --dport 22,80,443 -j ACCEPT

Se você presta suporte a partir de uma conexão com IP fixo, pode tornar a regra mais específica, permitindo o acesso apenas a partir deste endereço IP específico, como em:

# Abre uma porta para um IP específico:
iptables -A INPUT -p tcp -s 200.231.14.16 --dport 22 -j ACCEPT

Em um micro doméstico, você pode abrir também as portas usadas pelo bittorrent (6881 a 6889) ou portas usadas por jogos multiplayer, por exemplo. Para abrir um intervalo de portas, indique a primeira e a última porta, separadas por ":", como em:

# Abre um intervalo de portas:
iptables -A INPUT -p tcp --dport 6881:6889 -j ACCEPT

Além de trabalhar com endereços IP, é possível criar regras baseadas também em endereços MAC. Isso permite adicionar uma camada extra de proteção ao criar regras para a rede local. Para isso, usamos o parâmetro "-m mac --mac-source", seguido pelo endereço MAC da placa do host desejado. Para permitir que o host "192.168.1.100" tenha acesso ao servidor, mas apenas depois de verificado também o endereço MAC da interface de rede, você usaria uma regra como:

# Verifica tanto o endereço IP quanto o MAC antes de autorizar a conexão:
iptables -A INPUT -s 192.168.1.100 -m mac --mac-source 00:11:D8:76:59:2E -j ACCEPT

Note que agora, além do IP, especificamos o endereço MAC da placa. As duas regras são usadas em conjunto, de forma que o acesso é permitido apenas caso as duas informações estejam corretas. Isso dificulta as coisas para alguém que queira acessar o servidor trocando o IP da máquina. Você pode descobrir o MAC das máquinas da rede usando o próprio ifconfig ou o comando "arp -a".

Note que limitar o acesso com base no endereço MAC adiciona uma camada extra de proteção, mas não é infalível. O endereço MAC pode ser trocado de forma quase tão simples quanto o endereço IP e, sniffando a rede, é possível descobrir os endereços IP e MAC dos micros com uma certa facilidade.

No Linux, você pode trocar o endereço MAC da placa de rede usando os comandos:

# ifconfig eth0 down
# ifconfig eth0 hw ether 00:11:D8:76:59:2E
# ifconfig eth0 up


Como vê, basta especificar o endereço desejado. O Iptables não é capaz de diferenciar máquinas com os endereços MAC falseados das reais, de forma que se alguém desconectasse o micro "192.168.1.100" da rede (desconectando o cabo no switch, por exemplo) e configurasse outro para usar o mesmo endereço IP e o mesmo MAC, poderia acessar o servidor bipassando a regra de firewall. A única forma de ter uma segurança completa seria utilizar o SSH ou outro protocolo que utilize um algoritmo robusto de encriptação para o login e a transmissão dos dados.

Lembre-se de que o firewall é uma primeira barreira de proteção, mas não é uma garantia por si só. É preciso combiná-lo com outras camadas de segurança para ter um servidor completamente seguro.

Outra limitação é que as regras baseadas em endereços MAC podem ser usadas apenas dentro da rede local. Os roteadores descartam os endereços MAC dos pacotes antes de transmiti-los para a Internet, enviando apenas o endereço IP. Ao acessar através de uma conexão compartilhada, todos os pacotes provenientes da Internet chegam com o endereço MAC do gateway da rede.

Este é um exemplo de script completo, incluindo algumas regras adicionais para evitar ataques comuns. Ele inclui as funções para aceitar os comandos "start", "stop" e "restart", de forma a se comportar como se fosse um serviço de sistema:

#!/bin/bash
iniciar(){
# Abre para a faixa de endereços da rede local:
iptables -A INPUT -s 192.168.1.0/255.255.255.0 -j ACCEPT
# Faz a mesma coisa, só que especificando a interface. Pode ser
# usada em substituição à regra anterior:
# iptables -A INPUT -i eth0 -j ACCEPT
# Abre uma porta (inclusive para a Internet):
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# Ignora pings:
iptables -A INPUT -p icmp --icmp-type echo-request -j DROP
# Protege contra IP spoofing:
echo 1 > /proc/sys/net/ipv4/conf/default/rp_filter
# Descarta pacotes malformados, protegendo contra ataques diversos:
iptables -A INPUT -m state --state INVALID -j DROP
# Abre para a interface de loopback. Esta regra é essencial para que
# o KDE e outros programas gráficos funcionem adequadamente:
iptables -A INPUT -i lo -j ACCEPT
# Impede a abertura de novas conexões, efetivamente bloqueando o acesso
# externo ao seu servidor, com exceção das portas e faixas de endereços
# especificadas anteriormente:
iptables -A INPUT -p tcp --syn -j DROP
echo "Regras de firewall ativadas"
}
parar(){
iptables -F
iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
echo "Regras de firewall desativadas"
}
case "$1" in
"start") iniciar ;;
"stop") parar ;;
"restart") parar; iniciar ;;
*) echo "Use os parâmetros start ou stop"
esac

A receber qualquer conexão, vinda de qualquer endereço, o firewall primeiro verifica todas estas regras, seqüencialmente, para decidir se o pacote passa ou não. Usando este script de exemplo, teríamos o seguinte:

- Se o pacote vier da rede local, ele é aceito.

- Se o pacote for para porta 22 (do SSH), ele é aceito.

- Se for um ping, ele é ignorado (de forma a dificultar um pouco para outros descobrirem que você está online).

- Pacotes inválidos, que não façam parte de uma conexão aberta anteriormente e que não correspondam à abertura de uma nova conexão são ignorados, protegendo contra pacotes forjados e tentativas de ataque diversas.

- Se o pacote vier da sua própria máquina (um programa tentando mostrar alguma coisa na tela, por exemplo), ele é aceito.

- Se o pacote for uma resposta a uma conexão que você iniciou, como, por exemplo, o servidor do guiadohardware.net enviando a página do site que você está acessando, ele é aceito.

- Tentativas de conexão (toda conexão TCP é iniciada por um pacote syn) fora das condições especificadas acima são descartadas pelo firewall. A conexão nem sequer chega a ser estabelecida e o emissor não recebe qualquer resposta (DROP).

Para usar o script, transforme-o em um arquivo executável, usando o comando:

# chmod +x /etc/init.d/compartilhar

A partir daí, você pode iniciar e parar o compartilhamento usando os comandos:

# /etc/init.d/compartilhar start
# /etc/init.d/compartilhar stop


Para que o script seja executado durante o boot, você pode adicionar o comando "/etc/init.d/compartilhar start" no arquivo "/etc/rc.local", em vez de colocar os comandos diretamente.

Outra opção (mais elegante) é criar um link para ele dentro da pasta "/etc/rc5.d", o que também faz com que ele seja executado durante o boot:

# cd /etc/rc5.d
# ln -s ../init.d/compartilhar S21compartilhar


O "S" indica que o script deve ser executado com o parâmetro "start" e o "21" indica a ordem em que deve ser executado durante o boot, em relação aos outros serviços. A ordem de execução dos serviços muda de distribuição para distribuição, mas nessa posição garantimos que ele será executado depois da ativação das interfaces de rede e de outros serviços essenciais.

Se você é um administrador paranóico, verifique a configuração dos serviços na distribuição em uso e altere a ordem de inicialização do script de firewall, de forma que ele seja carregado antes de qualquer outro serviço que aceite conexões, como o Samba ou o Apache. Com isso você garante que o firewall será carregado primeiro e não fica com seu servidor vulnerável nem mesmo por um curto espaço de tempo durante o boot.

Isso nos leva a uma terceira opção para salvar a configuração, utilizando os próprios arquivos de inicialização do sistema. Ela é a mais "correta" do ponto de vista técnico, embora menos flexível. Nesse caso, a configuração seria feita em três passos:

A primeira parada seria o arquivo "/etc/modules", onde são listados os módulos carregados pelo sistema durante o boot. Nele seria adicionada a linha "iptables_nat", ativando o carregamento do módulo. Em seguida, você adicionaria (ou descomentaria) a linha "net.ipv4.conf.default.forwarding=1" no arquivo "/etc/sysctl.conf", para ativar o roteamento de pacotes, tornando permanente o comando "echo 1 > /proc/sys/net/ipv4/ip_forward".

Finalmente, depois de executar o comando "iptables -t nat -A POSTROUTING -o $placa -j MASQUERADE", que efetivamente ativa o compartilhamento, você usaria o comando "/etc/init.d/iptables save active" (nas derivadas do Debian) ou "service iptables save" (nas derivadas do Red Hat) para salvar regra e fazer com que ela passe a ser reativada durante o boot.

Continuando, outra dica importante são os comandos usados para limpar as regras do Iptables. É necessário executá-los sempre que você fizer alterações no seu script de firewall e quiser executá-lo novamente para que as novas regras entrem em vigor. Você pode notar que incluí o comando "iptables -F" como parte da função "stop" do script, de forma que ao desativar e reativar o script, as regras antigas seriam eliminadas e as novas regras carregadas. Além dele temos também o "iptables -t nat -F" e o "iptables -L":

iptables -F: Limpa a tabela principal do iptables, onde vão os comandos para abrir e fechar portas, que vimos até aqui.

iptables -t nat -F: Limpa a tabela nat, que é usada por regras que compartilham a conexão e fazem forwarding de portas. Todas as regras do Iptables que levam "-t nat" são armazenadas nesta segunda tabela, que precisa ser zerada separadamente. A idéia é que você pode limpar as regras principais do firewall sem desabilitar o compartilhamento da conexão e vice-versa.

iptables -L: Este comando lista a configuração atual, sem alterar nada. É interessante executá-lo depois de fazer alterações na configuração do firewall, para ter certeza que as regras surtiram o efeito esperado. Para ver as regras de forwarding e compartilhamento, use também o "iptables -t nat -L".

Este é um tutorial de três partes. Na segunda parte, iremos aprofundar esta configuração, gerando um script de firewall mais elaborado, voltado para um servidor de rede local, configurado como gateway da rede e, na terceira parte, estudaremos sobre a criação de scripts destinados a serem usados em um servidor de Internet.

Na primeira parte do tutorial, geramos um script de firewall simples, destinado a compartilhar a conexão e bloquear as conexões de entrada, permitindo apenas que o servidor fosse acessado remotamente via SSH. Vamos agora aprimorar a configuração, gerando um script de firewall mais elaborado, voltado para um servidor de rede local, configurado como gateway da rede.

Na verdade, as regras para compartilhamento da conexão e para a ativação do proxy transparente também são regras de firewall, apenas usadas para um propósito diferente. Em vez de criar dois scripts separados, um para compartilhar a conexão e outro para o firewall, você pode simplesmente adicionar as regras de restrição de acesso no seu script de compartilhamento da conexão, gerando um script unificado. Nesse caso, tome o cuidado de sempre colocar as regras que compartilham a conexão e ativam o proxy transparente antes das regras que bloqueiam conexões.

Este é um exemplo de script de firewall que inclui as regras para compartilhar a conexão e ativar o proxy transparente. Ao usá-lo, comente as linhas que não se aplicam à sua instalação e substitua o "eth1" e o "eth0" pelas interfaces da Internet e da rede local, caso diferente:

#!/bin/bash
iniciar(){
# Compartilha a conexão:
modprobe iptable_nat
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE
echo "Compartilhamento ativado"
# Proxy transparente:
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 3128
echo "Proxy transparente ativado"
# Permite conexões na interface de rede local e na porta 22:
iptables -A INPUT -i eth0 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# Regras básicas de firewall:
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -p icmp --icmp-type echo-request -j DROP
echo 1 > /proc/sys/net/ipv4/conf/default/rp_filter
iptables -A INPUT -p tcp --syn -j DROP
# Bloqueia as portas UDP de 0 a 1023:
iptables -A INPUT -p udp --dport 0:1023 -j DROP
echo "Regras de firewall e compartilhamento ativados"
}
parar(){
iptables -F
iptables -t nat -F
iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
echo 0 > /proc/sys/net/ipv4/ip_forward
echo "Regras de firewall e compartilhamento desativados"
}
case "$1" in
"start") iniciar ;;
"stop") parar ;;
"restart") parar; iniciar ;;
*) echo "Use os parâmetros start ou stop"
esac

Veja que agora a função "parar" do script inclui também os comandos "iptables -t nat -F" e "echo 0 > /proc/sys/net/ipv4/ip_forward", destinados a limpar as regras de roteamento e desativar o encaminhamento de pacotes quando o script é desativado, parando também o compartilhamento da conexão.

Outra novidade é a regra que bloqueia as portas UDP de 0 a 1023, adicionada no final do script. Ao contrário do TCP, o protocolo UDP não é baseado na abertura de conexões, os dados são simplesmente enviados diretamente, sem serem precedidos por um pacote SYN ou qualquer aviso. Por isso, não é possível utilizar uma regra que bloqueie a abertura de novas conexões UDP mas permita respostas a conexões iniciadas por você, como no caso da "iptables -A INPUT -p tcp --syn -j DROP". No caso das portas UDP é tudo ou nada, ou seja, ou você mantém a porta aberta para qualquer tipo de pacote, ou a fecha completamente.

Não podemos simplesmente bloquear todas as portas UDP, pois elas são usadas para o recebimento de requisições DNS. Você pode fazer o teste limpando as regras de firewall e usando a regra "iptables -A INPUT -p tcp --syn -j DROP", que fecha todas as portas UDP; tente navegar e você verá que a resolução de nomes parará de funcionar até que você remova a regra usando o "iptables -F". Entretanto, podemos bloquear as portas UDP privilegiadas, que são as usadas pelos serviços conhecidos. Este acaba sendo um bom meio-termo.

Forwarding de portas: Ao compartilhar uma conexão via NAT, apenas o servidor recebe conexões vindas da Internet. Os micros da rede local acessam através do servidor e recebem apenas pacotes de resposta. Na maioria dos casos, é justamente isso que você deseja, já que apenas o servidor fica exposto a ataques diretos, enquanto as estações ficam protegidas dentro da rede local. Entretanto, isso nos leva a outro problema, que são os casos em que você realmente deseja que algum dos hosts fique diretamente acessível.

Imagine que você queira que um servidor web, escutando na porta 80 do micro 192.168.1.3 da rede local, fique disponível para a Internet. Como o servidor é o único com um IP válido na Internet, a única forma de fazer com que o 192.168.1.3 fique acessível é fazer com que o servidor "passe a bola" para ele ao receber conexões na porta 80. É justamente isso que fazemos ao configurar o forwarding de portas. Uma vez feita a configuração, sempre que o servidor receber uma conexão qualquer na porta 80 (ou qualquer outra definida por você), ele a repassará para o 192.168.1.3. Isso é feito de forma completamente transparente, de forma que o emissor nem percebe que quem respondeu à solicitação foi outro host.

Essa opção pode ser usada também para permitir que os micros da rede local fiquem com as portas do bittorrent abertas (de forma a baixar arquivos com um melhor desempenho), rodem servidores de games online ou qualquer outra tarefa onde seja necessário manter determinadas portas TCP ou UDP abertas. A limitação é que continua existindo uma única porta 80, uma única porta 22, etc., de forma que apenas um micro da rede interna pode receber cada porta de cada vez.

Veja um exemplo de como redirecionar as portas 6881 a 6889 usadas pelo Bittorrent para o host 192.168.1.10 da rede local:

# Redireciona uma faixa de portas para um micro da rede local:
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A PREROUTING -p tcp -i eth1 --dport 6881:6889 -j DNAT
--to 192.168.1.10
iptables -t nat -A POSTROUTING -d 192.168.1.10 -j SNAT --to 192.168.1.1

Esta regra é um pouco mais complexa, pois trabalha em duas fases. A primeira faz com que o servidor encaminhe todas as conexões que receber na interface e porta especificada para o micro da rede local e a segunda faz com que os pacotes de resposta enviados por ele posam ser encaminhados de volta. Para que ambas funcionem, é necessário usar o comando "echo 1 > /proc/sys/net/ipv4/ip_forward", que ativa o forwarding de portas. É o mesmo comando que usamos ao compartilhar a conexão.

Nos parâmetros que coloquei em negrito, a "eth1" é a placa de Internet, onde chegam os pacotes, a "6881:6889" é a faixa de portas que está sendo redirecionada e o "192.168.1.10" é o IP do micro dentro da rede local que passa a receber as conexões. Na segunda regra, temos repetido o IP do micro na rede local e, em seguida, o "192.168.1.1" que indica o IP do servidor, dentro da rede local.

Para redirecionar uma única porta, ao invés de uma faixa, basta citar a porta, sem usar os ":", como em:

# Redireciona uma única porta para um micro da rede local.
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A PREROUTING -p tcp -i eth1 --dport 22 -j DNAT --to 192.168.1.10
iptables -t nat -A POSTROUTING -d 192.168.1.10 -j SNAT --to 192.168.1.1

É possível ainda indicar uma lista de portas (usando a opção -m multiport), como em:

# Redireciona um conjunto de portas
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A PREROUTING -p tcp -i eth1 -m multiport --dport 21,22,80 -j DNAT
--to-dest 192.168.1.10
iptables -t nat -A POSTROUTING -d 192.168.1.10 -j SNAT --to 192.168.1.1

Note que, nos três exemplos, usei o parâmetro "-p tcp". Embora necessário, ele faz com que a regra se aplique apenas a portas TCP. Caso você precise fazer forwarding de portas UDP, deve alterar o protocolo dentro da regra, como em:

# Redireciona uma porta UDP
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A PREROUTING -p udp -i eth1 --dport 53 -j DNAT --to 192.168.1.10
iptables -t nat -A POSTROUTING -d 192.168.1.10 -j SNAT --to 192.168.1.1

Bloqueando portas de saída: Mais um uso importante para o firewall é bloquear portas de saída, ou seja, bloquear portas no sentido rede local > Internet. Isso permite bloquear o uso de determinados programas que utilizem estas portas.

O MSN, por exemplo, utiliza originalmente a porta 1863. Nas versões recentes ele é capaz de se conectar também através da porta 80 (ou através de sites como o meebo.com, que permitem acessar o MSN diretamente através do navegador). Por isso, ao bloquear a porta 1863, os clientes podem continuar conseguindo se conectar, porém, você obriga o tráfego a passar pela porta 80, onde tem a chance de fazê-lo passar por um servidor Squid, configurado como proxy transparente. Isso permite logar os acessos ou sabotar o sistema de autenticação do MSN, bloqueando os domínios "messenger.hotmail.com" e "webmessenger.msn.com", além de outros sites que ofereçam clientes via web.

Hoje em dia, cada vez mais programas são capazes de acessar a Web através da porta 80, 443 ou via proxy, o que torna difícil bloqueá-los. Em muitos casos, é preciso usar uma combinação de portas fechadas no firewall, bloqueio a endereços IPs específicos e bloqueio de determinados domínios no Squid.

Ao criar as regras do Iptables, existem duas opções. Bloqueando a porta para "FORWARD", você impede o acesso a partir dos micros da rede local, que acessam através da conexão compartilhada pelo servidor. Bloqueando para "OUTPUT", a porta é bloqueada no próprio micro onde o firewall está ativo. Você pode bloquear as duas situações, duplicando a regra:

iptables -A OUTPUT -p tcp --dport 1863 -j REJECT
iptables -A FORWARD -p tcp --dport 1863 -j REJECT

Você pode ainda bloquear intervalos de portas, separando-as por ":", como em:

iptables -A FORWARD -p tcp --dport 1025:65536 -j REJECT

Como estamos criando regras para os micros da rede local e não para possíveis invasores provenientes da Internet, é aconselhável usar a regra "REJECT" ao invés de "DROP". Caso contrário, os programas nos clientes sempre ficarão muito tempo parados ao tentar acessar portas bloqueadas, o que vai gerar reclamações e um certo overhead de suporte.

Você pode descobrir facilmente quais portas de saída são utilizados por cada programa fazendo buscas no Google, mas tentar bloquear um a um todos os programas indesejados acaba sendo tedioso. Ao invés disso, você pode experimentar um solução mais radical: inverter a lógica da regra, bloqueando todas as portas de saída e abrindo apenas algumas portas "permitidas".

O mínimo que você precisa abrir neste caso são as portas 80 e 53 (DNS). A partir daí, você pode abrir mais portas, como a 25 (SMTP), 110 (POP3), 443 (HTTPS) e assim por diante. Um exemplo de configuração neste caso seria:

iptables -A FORWARD -p udp -i eth0 --dport 53 -j ACCEPT
iptables -A FORWARD -p tcp -i eth0 --dport 80 -j ACCEPT
iptables -A FORWARD -p tcp -i eth0 --dport 443 -j ACCEPT
iptables -A FORWARD -p tcp -i eth0 -j LOG
iptables -A FORWARD -p tcp -i eth0 -j REJECT

Veja que todas as regras especificam a interface da rede local (eth0 no exemplo), de onde serão recebidas as conexões dos clientes. Note que não incluí nenhum bloqueio para forwarding de pacotes provenientes da interface eth1 (da Internet), pois a idéia é bloquear diretamente as requisições dos clientes, e não as respostas. Em uma conexão TCP típica, o cliente envia a requisição na porta TCP usada pelo serviço, mas recebe a resposta em uma porta aleatória. Este é um exemplo de entrada no log do Iptables que mostra a resposta a uma conexão HTTP normal. Veja que ela está endereçada à porta 45159 do cliente:

IN=eth1 OUT=eth0 SRC=64.233.169.99 DST=192.168.0.10 LEN=40 TOS=0x00 PREC=0x00 TTL=239 ID=36813 PROTO=TCP SPT=80 DPT=45159 WINDOW=8190 RES=0x00 ACK FIN URGP=0

No caso da porta 53 (DNS), estou especificando o protocolo UDP ao invés de TCP, pois as requisições são feitas usando portas UDP para ganhar tempo. Embora os servidores DNS escutem tanto na porta 53 TCP, quanto UDP, a porta 53 TCP é utilizada apenas para transferência de zonas e não para resolução de nomes, já que ao usar UDP o tempo de resposta é menor. No UDP a requisição é simplesmente respondida da forma mais rápida possível, enquanto que no TCP é necessário abrir e encerrar a conexão.

A regra "iptables -A FORWARD -j LOG" é uma boa opção durante a fase de testes, pois ela faz com que o Iptables logue todos os pacotes que forem encaminhados (tanto envio, quanto resposta), permitindo que você verifique o que está ocorrendo quando algo não estiver funcionando. Você pode acompanhar o log usando o comando "dmesg".

Colocado nesta posição (depois das regras que autorizam as conexões nas portas 53 e 80), ele vai mostrar apenas as requisições bloqueadas pelo firewall, dando-lhe a chance de acompanhar os acessos dos clientes e permitir portas adicionais sempre que necessário.

Por exemplo, esta estrada (no log) mostra uma tentativa de conexão de um cliente MSN rodando no micro "192.168.1.10" que foi bloqueada pelo firewall:

IN=eth0 OUT=eth1 SRC=192.168.1.10 DST=207.46.28.77 LEN=60 TOS=0x00 PREC=0x00 TTL=63 ID=21328 DF PROTO=TCP SPT=38119 DPT=1863 WINDOW=5840 RES=0x00 SYN URGP=0

A opção "DTP" indica a porta usada. Se quisesse autorizar o uso do programa, você adicionaria a regra "iptables -A FORWARD -p tcp -i eth1 --dport 1863 -j ACCEPT" em seu script.

Outra opção, para não precisar abrir tantas portas e ter um melhor controle sobre o tráfego de saída é usar um servidor Squid configurado como proxy transparente (interceptando o tráfego da porta 80) e rodar servidores locais para DNS e e-mail (você pode configurar um servidor Postfix como sistema satélite, de forma que ele envie os e-mails dos usuários da rede usando o SMTP do provedor), de forma que qualquer acesso precise necessariamente passar por algum dos serviços ativos no servidor, sujeito a log e aos bloqueios que configurar.

Neste caso, desabilite o compartilhamento da conexão (ou bloqueie o forward de todas as portas) e configure os clientes para utilizarem o IP do servidor como DNS, servidor SMTP, POP e outros serviços que tenha ativado. Mesmo ao ser configurado como proxy transparente, o Squid continua funcionando como um proxy tradicional, através da porta 3128. Você pode configurar clientes de FTP e outros programas com suporte a proxy para acessarem através dele. A vantagem sobre o acesso direto é que ao passar pelo proxy, tudo fica registrado e todo acesso precisa passar pelos filtros de domínios, formatos de arquivos, limitação de banda, etc. definidos por você.

Complementando o bloqueio de portas, você pode também bloquear o acesso de determinados endereços IP, como em:

# Bloqueia o acesso à web a partir de um determinado IP
iptables -A FORWARD -p tcp -s 192.168.1.67 -j REJECT

Esta regra deve ir logo no início do script, antes das regras que abrem as portas de saída, caso contrário não surtirá efeito. Lembre-se de que o Iptables processa as regras seqüencialmente: se uma compartilha a conexão com todos os micros da rede, não adianta tentar bloquear para determinados endereços depois. As regras com as exceções devem sempre vir antes da regra mais geral.

Bloqueando domínios: É possível ainda bloquear ou permitir com base no domínio, tanto para entrada quanto saída. Isso permite bloquear sites e programas diretamente a partir do firewall, sem precisar instalar um servidor Squid e configurá-lo como proxy transparente. Nesse caso, usamos o parâmetro "-d" (destiny) do Iptables, seguido do domínio desejado.

Para bloquear os acessos ao Orkut, por exemplo, você usaria as regras:

iptables -A OUTPUT -d www.orkut.com -j REJECT
iptables -A FORWARD -d www.orkut.com -j REJECT

A primeira linha bloqueia pacotes de saída destinados ao domínio, ou seja, impede que ele seja acessado a partir da própria máquina local. A segunda linha bloqueia o forward de pacotes destinados a ele (domínio), ou seja, impede que outras máquinas da rede local, que acessam através de uma conexão compartilhada, acessem o domínio.

Se for paranóico, você pode usar também a regra:

iptables -A INPUT -s www.orkut.com -j DROP

Esta regra impede também que qualquer pacote proveniente do orkut.com chegue até a sua máquina. Como disse, é apenas para paranóicos.

Originalmente, o Iptables sabia trabalhar apenas com endereços IP. A possibilidade de criar regras baseadas em domínios é um recurso um pouco mais recente, onde o firewall faz um lookup do domínio, de forma a descobrir qual é o IP atual e assim poder bloqueá-lo. Você pode verificar o IP usado pelo servidor de um determinado domínio usando o comando "dig" (que no Debian faz parte do pacote "dnsutiuls"), como em:

$ dig orkut.com

A vantagem de criar as regras do firewall baseadas em domínios é que elas são automaticamente atualizadas caso o servidor do site mude de endereço.

Ao bloquear o "orkut.com" no Iptables, você automaticamente bloqueia o "www.orkut.com" ou qualquer outra variante do domínio que leve ao mesmo servidor. A principal limitação é que a regra não se aplica a subdomínios hospedados em diferentes servidores. Por exemplo, você pode bloquear o domínio "uol.com.br", mas isso não bloqueará o "tvuol.uol.com.br", que é hospedado em um servidor separado. Em casos como este, a única solução é bloquear ambos.

Assim como no caso do Squid, ao decidir bloquear o acesso a sites ou endereços diversos utilizando o Iptables, você vai logo acabar com uma lista relativamente grande de endereços a bloquear. Diferente do Squid, o Iptables não oferece uma opção para carregar a lista dos endereços que devem ser bloqueados a partir de um arquivo de texto, mas isso pode ser resolvido com um script simples, que leia o conteúdo do arquivo e gere as regras correspondentes.

Comece criando um arquivo de texto contendo os domínios ou endereços IP que deseja bloquear, um por linha, como em:

www.orkut.com
www.myspace.com
www.facebook.com

Em seguida, adicione esta função no início do seu script de firewall, especificando o arquivo de texto com os endereços:

for end in `cat /etc/bloqueados`
do
iptables -A OUTPUT -d $end -j REJECT
iptables -A FORWARD -d $end -j REJECT
done

Esta função usa o comando cat para ler o conteúdo do arquivo, gerando um par de regras do Iptables para cada um deles. O laço continua até gerar regras para todos os endereços incluídos no arquivo.

Na primeira parte do tutorial, geramos um script de firewall simples, destinado a compartilhar a conexão e bloquear as conexões de entrada. Na segunda parte, estudamos o uso de regras adicionais, destinadas ao uso em um servidor de rede local, configurado como gateway da rede. Nessa terceira e última parte, estudaremos sobre a configuração do firewall em servidores de Internet.

Ao configurar um servidor dedicado, o firewall é ainda mais importante, já que por possuir não apenas um endereço IP fixo, mas também ser acessível através de um domínio potencialmente bem conhecido, o servidor será alvo de ataques contínuos. Por um lado, a configuração é mais simples, já que você não precisará se preocupar com regras de roteamento e de encaminhamento de pacotes, como ao configurar o firewall do gateway da rede, mas, por outro, existe um conjunto de cuidados adicionais a tomar.

Um exemplo básico de script de firewall para uso em um servidor web seria:

#!/bin/bash

iniciar(){

# Abre para a interface de loopback:
iptables -A INPUT -p tcp -i lo -j ACCEPT

# Bloqueia um determinado IP. Use para bloquear hosts específicos:
#iptables -A INPUT -p ALL -s 88.191.79.206 -j DROP

# Abre as portas referentes aos serviços usados:

# SSH:
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# DNS:
iptables -A INPUT -p tcp --dport 53 -j ACCEPT
iptables -A INPUT -p udp --dport 53 -j ACCEPT

# HTTP e HTTPS:
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# Bloqueia conexões nas demais portas:
iptables -A INPUT -p tcp --syn -j DROP

# Garante que o firewall permitirá pacotes de conexões já iniciadas:
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# Bloqueia as portas UDP de 0 a 1023 (com exceção das abertas acima):
iptables -A INPUT -p udp --dport 0:1023 -j DROP

}
parar(){
iptables -F
iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
}

case "$1" in
"start") iniciar ;;
"stop") parar ;;
"restart") parar; iniciar ;;
*) echo "Use os parâmetros start ou stop"
esac

Se você está configurando um servidor dedicado remotamente, é importante que você teste o script antes de configurar o sistema para executá-lo automaticamente durante o boot. O motivo é simples: se houver alguma regra incorreta no script, que bloqueie seu acesso ao servidor, você poderá solicitar um reboot do servidor para que a configuração seja removida e você recupere o acesso. Entretanto, se o sistema for configurado para carregar o script durante o boot, o reboot não resolverá e você precisará abrir uma chamada de suporte, solicitando que um técnico se logue localmente no servidor e desative seu script (o que provavelmente resultará em uma taxa adicional).

Para evitar a possibilidade de precisar reiniciar o servidor para recuperar o acesso depois de uma configuração de firewall mal-sucedida, você pode usar um script simples, contendo as regras de firewall desejadas, seguidas de um sleep e comandos para limpar a configuração do firewall.

Presumindo que você não esteja usando regras de roteamento (da tabela NAT), um exemplo de bloco de comandos para incluir no final do script seria:

sleep 120
iptables -F
iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
iptables -X

Já conhecemos o "iptables -F", que limpa as regras do firewall. As opções "iptables -P INPUT ACCEPT" e "iptables -P OUTPUT ACCEPT" alteram a política padrão do firewall (caso por ventura ela tenha sido alterada anteriormente), fazendo com que ele reverta para o default, que é aceitar todos os pacotes, tanto de entrada quanto de saída. O "iptables -X" elimina qualquer tabela personalizada que tenha sido adicionada, garantindo que qualquer regra oculta de configuração seja eliminada.

O "sleep 120" é um contador, que faz com que o sistema espere dois minutos antes de continuar. Colocando os comandos no final do script de firewall, o sistema executaria os comandos que ativam o firewall, esperaria dois minutos e em seguida executaria os comandos que o desativam.

Com isso, as regras são desativadas automaticamente depois de alguns minutos; se você acabar trancado do lado de fora, vai precisar apenas esperar o tempo especificado e se conectar novamente. Só depois de testar o script e ter certeza de que ele está mesmo fazendo apenas o que deseja, você removeria os comandos de desativação e configuraria o sistema para ativá-lo automaticamente durante o boot.


Regras adicionais de segurança: Em um servidor dedicado, não faz muito sentido bloquear a resposta a pings, já que, de qualquer forma, ele precisará ficar com um conjunto de portas abertas. Ao invés de bloquear os pings, que afinal podem ser úteis em algumas situações, você pode limitar as respostas a apenas uma por segundo, evitando que alguém de má fé possa enviar um grande volume de pings (como ao usar o comando "ping -f"), como parte de um ataque DoS. Nesse caso, a regra seria:

iptables -A INPUT -p icmp --icmp-type echo-request -m limit --limit 1/s -j ACCEPT

Se seu servidor não irá atuar como um roteador, é prudente desativar o suporte a ICMP redirects. Este é um recurso utilizado por roteadores para alertar outros de que existe um melhor caminho para um determinado endereço ou rede, mas não tem uso legítimo em um servidor que não roteia pacotes:

echo 0 > /proc/sys/net/ipv4/conf/all/accept_redirects

Outra configuração desejada é desativar o suporte a ping broadcasts, um recurso que tem poucos usos legítimos e pode ser usado para fazer com que servidores participem involuntariamente de ataques DoS, enviando grandes quantidades de pings a outros servidores dentro da mesma faixa de endereços. Ele já vem desativado em quase todas as distribuições atuais, mas não custa verificar:

echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts


Mais uma opção que é importante manter desativada é o suporte ao source routing. Este é um recurso usado para testes de roteadores, que permite ao emissor especificar qual o caminho que o pacote tomará até o destino e também o caminho de volta. Ele é perigoso, pois permite falsear pacotes, fazendo com que eles pareçam vir de outro endereço e, ao mesmo tempo, fazer com que as respostas realmente sejam recebidas, permitindo abrir a conexão e transferir dados. Em outras palavras, se você incluiu regras que permitem o acesso de terminados endereços e esqueceu o suporte ao source routing ativo, um atacante que soubesse quais são os endereços autorizados poderia abrir conexões com o seu servidor se fazendo passar por um deles, um risco que você com certeza gostaria de evitar. Como o recurso não possui outros usos legítimos, é fortemente recomendável que você o mantenha desativado:

echo 0 > /proc/sys/net/ipv4/conf/all/accept_source_route

Diferente do servidor de rede local que compartilha a conexão, o servidor não deverá compartilhar a conexão, nem encaminhar pacotes de outros hosts. Você pode deixar isso explicito desativando o suporte a ip_forward:

echo 0 > /proc/sys/net/ipv4/ip_forward

Concluindo, temos o suporte a SYN cookies. Um dos tipos mais comuns de ataque DoS e também um dos mais efetivos é o SYN Flood. Este tipo de ataque consiste em enviar um grande volume de pacotes SYN até o alvo, sem nunca efetivamente abrir a conexão. Como os pacotes SYN possuem alguns poucos bytes, o ataque pode ser feito mesmo a partir de uma conexão doméstica.

Uma conexão TCP é iniciada através da troca de três pacotes entre o emissor e o destinatário, o famoso "three-way handshake". O emissor envia um pacote SYN, o destinatário responde com um pacote SYN/ACK e o emissor confirma, também enviando um pacote ACK. A conexão TCP fica então aberta por um certo tempo, até que a requisição da página, download do arquivo, ou outra operação em questão seja concluída.

Se o servidor recebe um pacote SYN solicitando a abertura da conexão, mas não recebe o pacote ACK de resposta, ele é obrigado a esperar até que o tempo limite seja atingindo, mantendo a conexão aberta. Como existe um limite de conexões TCP que o servidor pode manter ativas simultaneamente, um grande volume de pacotes SYN podem estourar o limite de conexões, fazendo com que o servidor deixe de responder a novas conexões, mesmo que exista banda disponível.

No Linux, isso pode ser evitado de forma bastante simples, ativando o uso de SYN Cookies, um recurso oferecido diretamente pelo Kernel, o que é feito com o comando abaixo, que pode ser incluído no seu script de firewall:

echo 1 > /proc/sys/net/ipv4/tcp_syncookies

Ao ativar o recurso, o sistema passa a responder ao pacote SYN inicial com um cookie, que identifica o cliente. Com isso, o sistema aloca espaço para a conexão apenas após receber o pacote ACK de resposta, tornando o ataque inefetivo. O atacante ainda pode consumir um pouco de banda, obrigando o servidor a enviar um grande volume de SYN Cookies de resposta, mas o efeito sobre o servidor será mínimo.

Concluindo, adicione também as regras que ativam o uso do rp_filter, de forma que o firewall sempre responda aos pacotes na mesma interface da qual eles foram originados, o que previne ataques diversos que tentem tirar proveito da regra que permite conexões na interface de loopback. Outra opção interessante é o bloqueio de pacotes inválidos, o que também melhora a segurança contra ataques diversos, incluindo pacotes enviados sem serem precedidos pelo envio do pacote SYN e da abertura da conexão:

echo 1 > /proc/sys/net/ipv4/conf/default/rp_filter
iptables -A INPUT -m state --state INVALID -j DROP

Juntando tudo, teríamos:

iptables -A INPUT -p icmp --icmp-type echo-request -m limit --limit 1/s -j ACCEPT
echo 0 > /proc/sys/net/ipv4/conf/all/accept_redirects
echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
echo 0 > /proc/sys/net/ipv4/conf/all/accept_source_route
echo 0 > /proc/sys/net/ipv4/ip_forward
echo 1 > /proc/sys/net/ipv4/tcp_syncookies
echo 1 > /proc/sys/net/ipv4/conf/default/rp_filter
iptables -A INPUT -m state --state INVALID -j DROP

Essas regras devem ser adicionadas logo no início do script, de forma que sejam carregadas antes de qualquer regra que abra portas ou permita o acesso de endereços ou faixa de endereços. Com isso, garantimos que elas serão aplicadas a todas as conexões, reduzindo a quantidade de buracos no firewall.


Resumo das regras do Iptables: Depois desta rodada de exemplos, nada melhor do que um guia mais detalhado dos parâmetros suportados pelo Iptables. Escrever regras de firewall é quase como aprender um novo dialeto. Existem muitas combinações possíveis entre os parâmetros disponíveis e "regras de concordância", que determinam o que funciona e o que não. Imagine que ao escrever uma nova regra, você está explicando uma idéia. Tente ser claro para que seja entendido ;).

Parâmetros do Iptables:

-A INPUT: Especifica que a regra se aplica a pacotes de entrada, ou seja, pacotes recebidos pelo servidor, em qualquer interface.

-A OUTPUT: A regra se aplica a pacotes de saída, transmitidos pelo próprio servidor.

-A FORWARD: Este parâmetro é usado ao compartilhar a conexão com a Internet, permitindo que os micros da rede local acessem através do servidor. Os pacotes de outros micros, encaminhados pelo servidor, são tratados como "FORWARD", diferentemente dos pacotes transmitidos pelo próprio servidor, que são tratados como "OUTPUT". Você pode definir regras diferentes para cada situação.

-p tcp: Especifica que a regra se aplica a pacotes TCP, o que é o mais comum.

-p udp: Alguns serviços usam também portas UDP. Um bom exemplo são os servidores DNS, que escutam tanto na porta 53 TCP, quanto na 53 UDP. Este parâmetro permite definir regras que se aplicam a estes casos, abrindo ou fechando as portas UDP, como em:

iptables -A INPUT -p udp --dport 53 -j ACCEPT

A maioria das regras do Iptables exigem que você especifique o protocolo, fazendo com que você tenha que repetir a regra caso queira abrir uma porta simultaneamente para TCP e UDP. Ao executar algo como "iptables -A INPUT --dport 53 -j ACCEPT" (sem especificar o protocolo), você receberá um erro como:

iptables v1.3.3: Unknown arg `--dport'
Try `iptables -h' or 'iptables --help' for more information.

Nesses casos, você pode usar o parâmetro "-p ALL", que se aplica simultaneamente aos três protocolos (TCP, UDP e ICMP), sem que você precise incluir uma regra separada para cada um, como no exemplo da regra que bloqueia qualquer tipo de conexão proveniente de um determinado endereço:

iptables -A INPUT -p ALL -s 88.191.79.206 -j DROP

Como as portas UDP também são usadas por alguns serviços, é muito comum bloquear as portas de 0 a 1023 UDP, autorizando apenas as portas que realmente devem ficar abertas, como em:

iptables -A INPUT -p udp --dport 53 -j ACCEPT
iptables -A INPUT -p udp --dport 0:1023 -j DROP

Note que você nunca deve fechar todas as portas UDP, pois as portas altas são usadas aleatoriamente para pacotes de resposta para DNS e diversos outros protocolos. Alguns administradores mais paranóicos fecham todas as portas UDP até a 32000, por exemplo. Não existem muitos problemas em fechar uma faixa maior de portas, desde que você sempre deixe uma larga faixa de portas altas abertas, de forma a receber os pacotes de resposta.

Ao contrário do TCP, não é possível criar uma regra genérica para permitir todos os pacotes de resposta UDP (como a "iptables -A INPUT -p tcp --syn -j DROP"), pois no UDP não são abertas conexões. Os pacotes são simplesmente transmitidos diretamente, sem aviso prévio.

-p icmp: Além do TCP e UDP, existe o protocolo ICMP, usado para pacotes de controle, pings e envio de mensagens. Um exemplo de uso é a regra para desativar a resposta a pings que vimos há pouco. Na verdade, ela atua bloqueando o pedido de ping antes que ele seja repassado ao sistema:

iptables -A INPUT -p icmp --icmp-type echo-request -j DROP

-i eth0: A opção "-i" permite definir a interface onde os pacotes devem ser recebidos ou enviados. Por exemplo, usar uma regra como:

iptables -A INPUT -p tcp -j REJECT

... simplesmente desconectaria seu micro da rede, pois bloquearia comunicações em qualquer interface. Porém, se você especificasse a interface, ele bloquearia apenas pacotes recebidos através dela, como em:

iptables -A INPUT -i eth2 -p tcp -j REJECT

O mesmo se aplica quando você quer permitir conexões em determinadas portas, mas apenas a partir da placa de rede local. Para permitir conexões via SSH apenas a partir da placa eth0, você poderia usar:

iptables -A INPUT -i eth0 -p tcp --dport 22 -j ACCEPT

-o eth0: É similar ao parâmetro "-i", mas especifica uma interface de saída. Este parâmetro é menos usado, pois normalmente nos preocupamos em impedir que o firewall aceite conexões em determinadas portas, em vez de tentar interceptar as respostas. Entretanto, esta opção pode ser útil em casos em que você precisa fechar uma porta de saída apenas para determinada interface. Este é um exemplo de uso, onde bloqueio pacotes de saída na porta 1863 apenas para a placa eth1:

iptables -A OUTPUT -p tcp -o eth1 --dport 1863 -j DROP

--dport ou --destination-port: Especifica uma porta. O uso mais comum para esta opção é para abrir portas de entrada (e depois aplicar uma regra que fecha as demais), como na regra que abre para conexões na porta 22, que mostrei no exemplo anterior.

-s (source): O parâmetro "-s" permite especificar um endereço IP ou domínio de origem, de forma a aceitar ou recusar as conexões. Embora seja muito fácil forjar endereços IP dentro da rede local, as coisas são muito mais complicadas na Internet. Permitir o acesso a determinadas portas (como a do SSH) apenas para determinados endereços, ou faixas de endereços, é uma medida de segurança interessante em muitas situações.

Este é um exemplo de regra, que abre a porta 631 apenas para hosts dentro da faixa e máscara especificada:

iptables -A INPUT -p tcp -s 72.232.35.0/255.255.255.248 --dport 631 -j ACCEPT

-d (destiny): Destinado ao endereço IP ou domínio citado. É muito usado ao bloquear o acesso a determinados sites a partir dos micros da rede local como, por exemplo:

iptables -A FORWARD -d torrentreactor.net -j REJECT

-m mac --mac-source 00:11:D8:76:59:2E: Esta é a regra que permite especificar endereços MAC dentro de regras do Iptables que vimos há pouco. Ela é uma forma de dificultar o uso de endereços IP falseados para ganhar acesso ao servidor, pois permite relacionar o IP ao endereço MAC da placa instalada. Lembre-se, porém, que ela só pode ser usada em rede local e que os endereços MAC são quase tão fáceis de falsear quanto os endereços IP. Um exemplo de uso seria:

iptables -A INPUT --dport 22 -m mac --mac-source 00:11:D8:76:59:2E -j ACCEPT

--syn: Cria uma regra válida apenas para novas conexões, não impedindo que o outro micro responda a conexões iniciadas pelo servidor, como em:

iptables -A INPUT -p tcp --syn -j DROP

-j: É usado no final de cada regra, especificando uma ação, que pode ser:

-j ACCEPT : Aceita o pacote. Ele é encaminhado ao destino sem passar pelas demais regras.

-j REJECT : Rejeita educadamente o pacote, enviando um pacote de resposta ao emissor. Quando uma porta está fechada em modo reject, o emissor recebe rapidamente uma resposta como "connect to host 192.168.1.1 port 22: Connection refused".

-j DROP: O DROP é mais enfático. O pacote é simplesmente descartado, sem aviso. O emissor fica um longo tempo esperando, até que eventualmente recebe um erro de time-out.

-j LOG: Este último parâmetro permite logar conexões. É interessante usar esta regra principalmente em portas muito visadas, como a do SSH, pois assim você tem uma lista de todos os endereços que acessaram seu servidor na porta especificada. Para ativar o log, você deve duplicar a regra que abre a porta, usando a opção "-j LOG" na primeira e "-j ACCEPT" na segunda, como em:

iptables -A INPUT -p tcp --dport 22 -j LOG
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

As mensagens são gravadas no arquivo "/var/log/messages" de forma bastante detalhada, incluindo a data e hora da conexão, o IP e MAC do micro que fez a conexão (SRC), além da porta (DPT). Você pode ver o mesmo log, porém com as entradas escritas de forma resumida, usando o comando "dmesg".
Jun 29 15:49:46 spartacus kernel: IN=eth0 OUT= MAC=00:e0:7d:9b:f8:01:00:15:00:4b:68:db:08:00 SRC=192.168.1.2 DST=192.168.0.1 LEN=52 TOS=0x00 PREC=0x00 TTL=64 ID=32704 DF PROTO=TCP SPT=56848 DPT=22 WINDOW=2164 RES=0x00 ACK URGP=0

Não se assuste com o volume de informações, pois o log inclui todas as tentativas de conexão. O fato de um determinado IP ter aberto uma conexão com a porta 22 do seu servidor, não significa que o usuário realmente obteve acesso ao SSH. Ele pode ter recebido o prompt para digitar a senha, mas isso não significa que ele realmente conseguiu fazer login.

Note que alterar a ordem das regras altera o resultado. Em caso de duas regras conflitantes, vale a que vem primeiro. Por exemplo, ao usar:

iptables -A INPUT -p tcp -j REJECT
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

... a porta 22 permanecerá fechada, pois os pacotes serão descartados pela primeira regra, sem terem chance de serem autorizados pela segunda. É justamente por isso que é sempre necessário colocar as regras menos restritivas primeiro, declarando as portas autorizadas, para só então fechar as demais.

O mesmo se aplica ao logar transmissões. Se você usar algo como:

iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j LOG

... o log não funcionará, pois os pacotes destinados à porta 22 serão aceitos pela primeira regra e não passarão pela segunda, que faz o log. As regras que fazem log devem sempre vir antes das regras que autorizam as conexões.

fonte : http://www.hardware.com.br/tutoriais/linux-escrevendo-scripts-firewall/

http://marquescsh.blogspot.com

demattos

demattos
MODERADOR
MODERADOR

Muito bom este tutorial, inclusive tenho este livro morimoto nuito bom e recomento quem estaja afim de ter um guia de bolso para pesquisas e aprendizado, rsrsrs mas quando comprei nao tinha tanto material assim na net, iptables e bem completo para para fazer um otimo firewall para sua rede.


abracoa todos

http://www.criciumanet.com.br

gussmaster


Iniciante
Iniciante

Primeiro , tópico que eu leio aqui e aprendi meio mundo de coisas xD !


Excelente tópico !

Marcio Marques

Marcio Marques
ADMINISTRADOR FUNDADOR
ADMINISTRADOR FUNDADOR

gussmaster escreveu:Primeiro , tópico que eu leio aqui e aprendi meio mundo de coisas xD !


Excelente tópico !

Agradecemos amigo !

Nós da equipe FPI não esperamos e arquivamos apenas tópicos e posts de usuários , pensamos em todos os dias criar uma grande biblioteca de informações centralizadas , para que quando visitarem nosso portal, acharem tudo que precisam aqui mesmo ...

Grande Abraço !

http://marquescsh.blogspot.com

Conteúdo patrocinado



Ir para o topo  Mensagem [Página 1 de 1]

Permissões neste sub-fórum
Não podes responder a tópicos