InfraFenceInfraFence

Live Security Operations

Começar

Como parar ataques de força bruta no SSH

Última atualização:

Qualquer servidor com a porta 22 aberta para a internet começa a receber tentativas de senha poucos minutos depois de ligado, o dia inteiro, de milhares de endereços. Quase sempre são bots testando root, admin e nomes comuns com listas de senhas vazadas. Eles só entram onde a senha é fraca, mas enchem os logs, consomem CPU, e basta uma conta fraca.

A solução é em camadas: tornar as senhas inúteis (só chaves), tirar o root da jogada e depois banir e limitar o que sobrar. Os comandos abaixo são para Debian e Ubuntu e para a família RHEL (RHEL, Rocky Linux, AlmaLinux, Oracle Linux, CentOS Stream, Fedora).

Verificar se você está sob ataque

O daemon do SSH registra cada tentativa que falha. Conte as das últimas 24 horas e depois veja quais endereços mandam mais:

Qualquer distribuição com systemd
sudo journalctl --since "24 hours ago" | grep -cE "Failed password|Invalid user"
Qualquer distribuição com systemd
sudo journalctl --since "24 hours ago" \
  | grep -E "Failed password|Invalid user" \
  | grep -oE "from [0-9a-fA-F.:]+ port" | awk '{print $2}' \
  | sort | uniq -c | sort -rn | head -20

Centenas ou milhares de linhas por dia são normais para um servidor com IP público. Se o journal não é mantido entre reinicializações, as mesmas linhas estão em /var/log/auth.log no Debian e no Ubuntu e em /var/log/secure na família RHEL.

Configurar as chaves SSH e testá-las antes de tudo

Tudo o que vem depois desliga as senhas, então primeiro você precisa de uma chave que funcione. No seu computador, crie uma chave, copie-a para o servidor e entre com ela. Troque deploy pelo seu usuário e SERVER_IP pelo endereço do servidor.

No seu computador
ssh-keygen -t ed25519 -C "laptop"
ssh-copy-id -i ~/.ssh/id_ed25519.pub deploy@SERVER_IP
ssh -i ~/.ssh/id_ed25519 deploy@SERVER_IP

O último comando tem que fazer você entrar sem pedir a senha da conta (ele pode pedir a passphrase da chave, que fica no seu computador).

Atenção: Daqui em diante, mantenha uma sessão SSH aberta no servidor e faça todos os testes em um segundo terminal. Se uma alteração deixar você sem acesso, é pela sessão aberta que você desfaz. Antes de começar, descubra também onde fica o console web do seu provedor (VNC ou serial): ele funciona sem SSH.

Criar um usuário sudo antes de desativar o root

Se hoje você entra como root, crie antes um usuário comum com permissão de sudo e dê a ele as mesmas chaves.

Debian / Ubuntu
sudo adduser deploy
sudo usermod -aG sudo deploy
RHEL, Rocky Linux, AlmaLinux, Oracle Linux, Fedora
sudo useradd -m deploy
sudo passwd deploy
sudo usermod -aG wheel deploy
Copiar as chaves do root para o novo usuário
sudo mkdir -p /home/deploy/.ssh
sudo cp /root/.ssh/authorized_keys /home/deploy/.ssh/
sudo chown -R deploy:deploy /home/deploy/.ssh
sudo chmod 700 /home/deploy/.ssh
sudo chmod 600 /home/deploy/.ssh/authorized_keys
Só na família RHEL, para os rótulos do SELinux
sudo restorecon -R /home/deploy/.ssh

No segundo terminal, entre com o novo usuário e rode sudo -v: ele tem que aceitar a senha do usuário. Só então siga em frente.

Desativar o login por senha e o login do root

As versões atuais de Debian, Ubuntu, família RHEL 9 e Fedora leem arquivos extras em /etc/ssh/sshd_config.d/. Confira se a sua faz isso:

Qualquer distribuição
grep -i '^Include' /etc/ssh/sshd_config

Se aparecer Include /etc/ssh/sshd_config.d/*.conf, coloque as configurações em um arquivo próprio. O SSH fica com o primeiro valor que lê para cada opção, e os arquivos são lidos em ordem alfabética, então o prefixo 00- ganha de arquivos como 50-cloud-init.conf, que em algumas imagens de nuvem religa as senhas.

Qualquer distribuição
sudo tee /etc/ssh/sshd_config.d/00-hardening.conf > /dev/null <<'EOF'
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no
MaxAuthTries 4
LoginGraceTime 30
EOF

Se não houver linha Include (RHEL 8 e derivados), defina as mesmas seis linhas no próprio /etc/ssh/sshd_config, substituindo as que já existem. Depois teste a configuração e veja os valores que o SSH vai usar de fato:

Qualquer distribuição
sudo sshd -t && echo "config OK"
sudo sshd -T | grep -Ei '^(pubkeyauthentication|passwordauthentication|kbdinteractiveauthentication|permitrootlogin|maxauthtries) '

Cada linha tem que mostrar o valor que você definiu. Se o root ainda precisa entrar com chave, para uma rotina de backup por exemplo, use PermitRootLogin prohibit-password em vez de no. Recarregue o SSH: as sessões abertas continuam conectadas.

Debian / Ubuntu
sudo systemctl reload ssh
RHEL, Rocky Linux, AlmaLinux, Oracle Linux, Fedora
sudo systemctl reload sshd

Atenção: Não feche a sessão aberta ainda. No segundo terminal, entre com a sua chave e depois confirme que a senha é recusada: o comando abaixo tem que terminar com Permission denied (publickey).

No seu computador
ssh -o PubkeyAuthentication=no -o PreferredAuthentications=password deploy@SERVER_IP

Mudar a porta do SSH, sabendo o que isso não resolve

Tirar o SSH da porta 22 reduz o ruído nos logs, porque a maioria dos bots só tenta a 22. Isso não deixa o SSH mais seguro: scanners de portas acham a nova porta em poucas horas, e um atacante com alvo definido acha na hora. Com login só por chave, a porta pouco importa. Faça isso para ter logs mais limpos, não por segurança, e só depois dos passos anteriores.

Escolha uma porta (aqui, 2222), libere-a no firewall e, na família RHEL, avise o SELinux de que o SSH pode usá-la:

Debian / Ubuntu com ufw
sudo ufw allow 2222/tcp
Família RHEL com firewalld e SELinux
sudo firewall-cmd --permanent --add-port=2222/tcp
sudo firewall-cmd --reload
sudo dnf install -y policycoreutils-python-utils
sudo semanage port -a -t ssh_port_t -p tcp 2222

Libere a porta também no firewall de nuvem ou no security group do provedor. Depois defina a porta e reinicie o SSH:

Qualquer distribuição
echo "Port 2222" | sudo tee /etc/ssh/sshd_config.d/01-port.conf
sudo sshd -t && echo "config OK"

A partir do Ubuntu 24.04, o SSH pode ser iniciado pelo ssh.socket: se o primeiro comando abaixo mostrar active, rode as quatro linhas; caso contrário, só a última.

Debian / Ubuntu
systemctl is-active ssh.socket
sudo systemctl daemon-reload
sudo systemctl restart ssh.socket
sudo systemctl restart ssh
RHEL, Rocky Linux, AlmaLinux, Oracle Linux, Fedora
sudo systemctl restart sshd
No seu computador
ssh -p 2222 deploy@SERVER_IP

Atenção: Só quando o login na nova porta funcionar, remova do firewall a regra da porta 22. O fail2ban, o sshguard e os limites de taxa abaixo também precisam usar a nova porta.

Banir quem insiste com fail2ban ou sshguard

Com as senhas desligadas, as tentativas não têm como dar certo, mas banir os endereços que continuam tentando reduz a carga e o ruído. O fail2ban lê o log e bane um endereço no firewall depois de um certo número de falhas.

Debian / Ubuntu
sudo apt update
sudo apt install -y fail2ban python3-systemd
Rocky Linux, AlmaLinux, CentOS Stream (EPEL)
sudo dnf install -y epel-release
sudo dnf install -y fail2ban

No RHEL propriamente dito e no Oracle Linux, ative o EPEL como a documentação deles indica e depois instale o fail2ban. No Fedora ele está nos repositórios principais. O Amazon Linux 2023 não pode usar o EPEL: use o limite de taxa no firewall, mais abaixo.

As configurações vão no jail.local, nunca no jail.conf, que as atualizações sobrescrevem. Confira se você ainda não tem um e depois crie. Troque YOUR_OFFICE_IP pelos endereços fixos de onde você trabalha, ou apague, e ajuste port para a sua porta SSH se você a mudou.

Qualquer distribuição
ls -l /etc/fail2ban/jail.local
Qualquer distribuição
sudo tee /etc/fail2ban/jail.local > /dev/null <<'EOF'
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 YOUR_OFFICE_IP
bantime = 1h
bantime.increment = true
findtime = 10m
maxretry = 5

[sshd]
enabled = true
backend = systemd
port = ssh
EOF

Assim, um endereço é banido por uma hora depois de 5 falhas em 10 minutos, e por mais tempo a cada vez que volta. backend = systemd lê o journal, o que funciona no Debian 12 e posteriores, onde /var/log/auth.log pode não existir.

Qualquer distribuição
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd

Durante um ataque, Total failed e Currently banned sobem em poucos minutos. Se Total failed fica em 0 enquanto o journal mostra logins com falha, a jail não está lendo o log certo. Para remover um banimento:

Qualquer distribuição
sudo fail2ban-client set sshd unbanip 203.0.113.7

sshguard, a alternativa mais leve

O sshguard faz o mesmo trabalho com menos configuração e tem pacote no Debian e no Ubuntu (e no EPEL). Coloque primeiro os seus endereços na whitelist dele e depois acompanhe sudo journalctl -u sshguard -f durante um ataque para ver os bloqueios. Use um dos dois, não os dois juntos.

Debian / Ubuntu
sudo apt install -y sshguard
echo "YOUR_OFFICE_IP" | sudo tee -a /etc/sshguard/whitelist
sudo systemctl restart sshguard

Limitar ou restringir o SSH no firewall

No Ubuntu e no Debian com ufw, o limit recusa um endereço que abre 6 ou mais conexões em 30 segundos. Ele substitui uma regra simples allow 22/tcp. Se sudo ufw status também mostrar uma regra OpenSSH, apague-a depois que o limite estiver valendo (sudo ufw delete allow OpenSSH): ela seria aplicada antes do limite.

Debian / Ubuntu com ufw
sudo ufw limit 22/tcp
sudo ufw enable
sudo ufw status verbose

Atenção: Se o ufw ainda não está ativo, ufw enable passa a bloquear toda porta sem regra. Libere os serviços que o servidor oferece (por exemplo sudo ufw allow 80,443/tcp) antes de ativá-lo, e mantenha a sessão aberta.

As rich rules do firewalld têm um limit, mas ele conta todas as origens juntas, então um ataque pode esgotar a cota e deixar você de fora também. Na família RHEL, use o fail2ban para limites por endereço.

Permitir SSH só a partir dos seus endereços

O passo mais forte, quando você trabalha de endereços fixos ou por uma VPN: ninguém mais consegue nem chegar ao SSH.

Debian / Ubuntu com ufw
sudo ufw allow from YOUR_OFFICE_IP to any port 22 proto tcp
sudo ufw delete limit 22/tcp
sudo ufw status numbered
Família RHEL com firewalld
sudo firewall-cmd --permanent --zone=trusted --add-source=YOUR_OFFICE_IP
sudo firewall-cmd --reload
sudo firewall-cmd --permanent --zone=public --remove-service=ssh
sudo firewall-cmd --reload

Atenção: Isso bloqueia todos os outros endereços, inclusive o seu se ele mudar. Teste um novo login depois do primeiro reload e antes de remover a regra pública do SSH, e tenha o console web do provedor como caminho de volta.

Como o InfraFence lida com força bruta no SSH

O agente do InfraFence lê o log do SSH à medida que ele é escrito e bane um endereço no firewall quando ele atinge o limite de falhas dentro da janela de tempo, dois valores que você pode mudar no painel.

  • 15 padrões de detecção: senhas erradas, usuários inválidos, falhas de PAM, varreduras antes da autenticação, protocolos incompatíveis e conexões derrubadas na troca de chaves.
  • Banimentos progressivos: 24 horas, 7 dias, 30 dias e depois permanente, ou a duração que você definir. Opcionalmente, um endereço banido em um servidor é banido em todos os seus servidores.
  • A mesma proteção para os logins de Postfix, Dovecot, MySQL, PostgreSQL, MongoDB, Pure-FTPd, ProFTPD e vsftpd.
  • As verificações de hardening apontam login do root, login por senha, a porta padrão e um MaxAuthTries alto. O MaxAuthTries se corrige com um clique, em um arquivo próprio (/etc/ssh/sshd_config.d/00-infrafence-hardening.conf) que é testado antes de o SSH ser recarregado. Login do root, senhas e porta podem deixar você sem acesso, por isso são explicados passo a passo, como neste guia.
  • Cada sessão SSH é acompanhada do login ao logout e recebe uma pontuação de risco, para você saber quem estava conectado quando algo mais disparou.

Ele funciona ao lado do fail2ban: o agente o reconhece e mantém as próprias regras em cadeias INFRAFENCE separadas, que ele recoloca depois de um reload do firewall.

Perguntas

Mudar a porta do SSH basta para parar a força bruta?
Não. Reduz o número de tentativas nos logs, porque a maioria dos bots só tenta a porta 22, mas os scanners acham a nova porta rápido. O que torna as tentativas inúteis é o login só por chave.
Devo usar fail2ban ou sshguard?
Para SSH, qualquer um dos dois serve. O fail2ban tem mais filtros para outros serviços e mais opções; o sshguard exige menos configuração. Rode um só, não os dois, para eles não brigarem pelos mesmos endereços.
Desativei as senhas e continuo vendo logins com falha. Tem algo errado?
Não. Os bots continuam tentando porque não sabem que as senhas estão desligadas. As tentativas falham antes de qualquer senha ser verificada. Banimentos e limites de taxa reduzem o ruído.

Teste grátis em 1 servidor

O Starter é gratuito para um servidor, com proteção completa e bloqueio automático. Sem cartão de crédito.

Instale o agente como root, com o seu token no lugar de <TOKEN>:

curl -fsSL https://github.com/infrafence/infrafence-agent/releases/latest/download/install.sh | sudo bash -s -- --token <TOKEN>

O token é criado no painel, em Servidores › Adicionar servidor.