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:
sudo journalctl --since "24 hours ago" | grep -cE "Failed password|Invalid user"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 -20Centenas 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.
ssh-keygen -t ed25519 -C "laptop"
ssh-copy-id -i ~/.ssh/id_ed25519.pub deploy@SERVER_IP
ssh -i ~/.ssh/id_ed25519 deploy@SERVER_IPO ú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.
sudo adduser deploy
sudo usermod -aG sudo deploysudo useradd -m deploy
sudo passwd deploy
sudo usermod -aG wheel deploysudo 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_keyssudo restorecon -R /home/deploy/.sshNo 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:
grep -i '^Include' /etc/ssh/sshd_configSe 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.
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
EOFSe 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:
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.
sudo systemctl reload sshsudo systemctl reload sshdAtençã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).
ssh -o PubkeyAuthentication=no -o PreferredAuthentications=password deploy@SERVER_IPMudar 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:
sudo ufw allow 2222/tcpsudo 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 2222Libere a porta também no firewall de nuvem ou no security group do provedor. Depois defina a porta e reinicie o SSH:
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.
systemctl is-active ssh.socket
sudo systemctl daemon-reload
sudo systemctl restart ssh.socket
sudo systemctl restart sshsudo systemctl restart sshdssh -p 2222 deploy@SERVER_IPAtençã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.
sudo apt update
sudo apt install -y fail2ban python3-systemdsudo dnf install -y epel-release
sudo dnf install -y fail2banNo 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.
ls -l /etc/fail2ban/jail.localsudo 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
EOFAssim, 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.
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshdDurante 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:
sudo fail2ban-client set sshd unbanip 203.0.113.7sshguard, 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.
sudo apt install -y sshguard
echo "YOUR_OFFICE_IP" | sudo tee -a /etc/sshguard/whitelist
sudo systemctl restart sshguardLimitar 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.
sudo ufw limit 22/tcp
sudo ufw enable
sudo ufw status verboseAtençã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.
sudo ufw allow from YOUR_OFFICE_IP to any port 22 proto tcp
sudo ufw delete limit 22/tcp
sudo ufw status numberedsudo 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 --reloadAtençã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
MaxAuthTriesalto. OMaxAuthTriesse 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.
