Hardening de SSH: os ajustes que valem e os mitos que não
Trocar a porta 22 não protege quase nada. Estes são os ajustes que realmente mudam a superfície de ataque do seu servidor, na ordem em que compensa aplicá-los.
Equipe EasyOps Cloud · · 7 min de leitura
Um servidor com SSH aberto para a internet recebe entre dois e dez mil pedidos de autenticação por dia. Não é ataque direcionado — é varredura automatizada, constante, contra toda a faixa de IP pública que existe.
A boa notícia é que a defesa é curta e conhecida. A ruim é que metade do que se recomenda por aí não muda nada de relevante, e o tempo gasto ali é tempo que não foi gasto no que importa. Vamos separar os dois grupos.
O ajuste que sozinho resolve 95% do problema
Desligar autenticação por senha. Só isso já elimina a força bruta como categoria de risco, porque não existe senha para adivinhar.
A ordem importa, e inverter aqui é o jeito mais rápido de perder acesso à máquina. Primeiro instale a sua chave e teste que ela funciona:
# Do seu notebook
ssh-keygen -t ed25519 -C "seu@email"
ssh-copy-id usuario@203.0.113.50
ssh usuario@203.0.113.50 # tem que entrar sem pedir senhaSó depois de entrar sem senha, altere o servidor:
# /etc/ssh/sshd_config.d/99-hardening.conf
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yesO arquivo em sshd_config.d/ é preferível a editar o sshd_config direto: ele
sobrevive a atualização de pacote e deixa explícito o que foi alterado. Confirme
a sintaxe antes de recarregar, porque um erro aqui derruba o serviço:
sudo sshd -t && sudo systemctl reload sshMantenha a sessão atual aberta e teste em uma segunda janela. Se algo der
errado, você ainda tem a primeira para desfazer. E se mesmo assim o acesso cair,
o console no browser entra pela virtualização em vez da rede — continua
funcionando com o sshd parado, o que transforma uma máquina perdida em cinco
minutos de correção.
O tipo de chave também mudou. ed25519 é o padrão atual: chave menor, verificação
mais rápida e sem os parâmetros que tornam RSA fácil de configurar mal. RSA só
se precisar falar com sistema antigo — e aí com 4096 bits, nunca 1024.
Root: não é sobre o login, é sobre o rastro
PermitRootLogin noO argumento comum é que root é alvo de força bruta. Com senha desligada isso já
não importa. A razão real é outra: quando todo mundo entra como root, o log
registra root em toda ação e você perde a resposta para "quem executou isto?".
Entrar com usuário nominal e escalar com sudo mantém o rastro em /var/log/auth.log
e permite revogar o acesso de uma pessoa sem trocar a senha de todo o time.
Se algum automatismo precisa de root — e isso acontece —, prefira uma chave dedicada com comando restrito em vez de liberar o login inteiro:
# /root/.ssh/authorized_keys
command="/usr/local/bin/deploy.sh",no-port-forwarding,no-pty ssh-ed25519 AAAA...Essa chave só consegue executar aquele script. Nem shell, nem túnel.
Restringir quem pode entrar
Por padrão, qualquer usuário do sistema com shell válido pode autenticar por SSH. Isso inclui contas de serviço criadas por pacotes que você instalou e esqueceu.
AllowUsers deploy crystian
# ou, gerenciando por grupo:
AllowGroups ssh-usersA forma por grupo escala melhor: adicionar alguém vira usermod -aG ssh-users
fulano, sem editar configuração nem recarregar serviço.
Vale combinar com restrição de origem no firewall. Se todo acesso administrativo
vem do IP do escritório ou de uma VPN, a regra de firewall que só libera a porta
22 para aquela faixa faz mais pelo servidor do que qualquer opção do sshd_config
— porque o pacote nem chega a ser processado. Só não caia na armadilha do IP
dinâmico: se o seu IP residencial muda, restringir por origem é um bloqueio
agendado contra você mesmo.
O que fazer com o barulho que sobra
Com senha desligada, as tentativas continuam chegando e falhando. Elas não são
mais risco de invasão, mas ainda consomem CPU, enchem log e atrapalham a leitura
de auth.log.
O fail2ban resolve o incômodo:
sudo apt install fail2ban# /etc/fail2ban/jail.local
[sshd]
enabled = true
maxretry = 4
findtime = 10m
bantime = 1hsudo systemctl enable --now fail2ban
sudo fail2ban-client status sshdVale ser honesto sobre o que ele entrega: com autenticação por senha desligada,
o fail2ban é higiene de log, não camada de segurança. Ele é indispensável quando
você não pode desligar senha; é conveniência quando pode.
Um detalhe que pega muita gente: bantime longo demais combinado com maxretry
baixo bane o próprio administrador que errou a chave três vezes. Deixe o seu IP
na lista de exceção:
ignoreip = 127.0.0.1/8 203.0.113.10Segundo fator, quando faz sentido
Chave SSH é algo que você tem. Se o notebook for comprometido, a chave vai junto. Para acesso a servidor com dado sensível, o segundo fator fecha essa lacuna:
sudo apt install libpam-google-authenticator
google-authenticator # como o usuário, não como root# /etc/ssh/sshd_config.d/99-hardening.conf
AuthenticationMethods publickey,keyboard-interactive
KbdInteractiveAuthentication yes# /etc/pam.d/sshd — no topo
auth required pam_google_authenticator.so nullokO nullok permite que quem ainda não configurou o TOTP continue entrando — útil
durante a transição, e a primeira coisa a remover quando todos já estiverem
migrados.
Guarde os códigos de recuperação em outro lugar que não o servidor. Perder o celular sem eles significa depender do console de emergência para voltar.
Auditar o acesso que já existe
Endurecer a configuração não adianta se três ex-funcionários continuam com chave válida. Antes de qualquer ajuste, vale saber quem entra hoje.
Comece pelas chaves autorizadas de cada conta:
sudo awk -F: '$7 !~ /nologin|false/ {print $1, $6}' /etc/passwd |
while read -r u h; do
[ -f "$h/.ssh/authorized_keys" ] && \
echo "== $u" && ssh-keygen -lf "$h/.ssh/authorized_keys"
doneA saída traz o *fingerprint*, o tipo e o comentário de cada chave. O comentário
é geralmente usuario@maquina e é a única pista de a quem a chave pertence —
motivo para exigir comentário descritivo ao cadastrar uma chave nova.
Depois, veja quem realmente usou o servidor:
last -F -n 40 # sessões recentes
sudo journalctl -u ssh --since '30 days ago' \
| grep 'Accepted' | awk '{print $9, $11}' | sort | uniq -c | sort -rnCruzar as duas listas costuma revelar duas coisas desconfortáveis: chave de gente que saiu da empresa, e conta de serviço com shell válido que ninguém lembra de ter criado.
A remoção é direta, e vale documentar o motivo em algum lugar que não seja o servidor:
sudo -u deploy sed -i '/fingerprint-ou-comentario/d' ~deploy/.ssh/authorized_keys
sudo usermod -s /usr/sbin/nologin conta-de-servicoFaça dessa auditoria um evento com data marcada — trimestral resolve. Chave SSH não expira sozinha, e é o único credencial da sua infraestrutura que tende a se acumular indefinidamente sem que nada avise.
Os mitos que não valem o esforço
- Trocar a porta 22. Reduz o volume de log de varredura burra e nada mais. Um
nmap -p-acha a porta nova em segundos. Se o objetivo é log limpo, ofail2banfaz melhor. Se é segurança, isto não é segurança. - Desabilitar o banner de versão. O
sshdnão permite omitir a versão do protocolo, e "esconder" a versão do OpenSSH não impede exploração de falha — impede apenas a listagem preguiçosa. Atualizar o pacote resolve de verdade. - Port knocking. Adiciona uma etapa frágil e difícil de operar em equipe para resolver um problema que a restrição por IP resolve melhor.
- Limitar `MaxAuthTries` a 1. Parece rigoroso, mas o cliente SSH tenta cada chave
do seu agente em sequência. Com três chaves carregadas, você é desconectado
antes de chegar na certa.
3a6é o intervalo razoável.
O conjunto mínimo defensável
# /etc/ssh/sshd_config.d/99-hardening.conf
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no
AllowGroups ssh-users
MaxAuthTries 4
LoginGraceTime 30
ClientAliveInterval 300
ClientAliveCountMax 2
X11Forwarding nosudo sshd -t && sudo systemctl reload sshOs dois ClientAlive derrubam sessão órfã de conexão que caiu — evita acumular
processo de shell de gente que fechou o notebook. O LoginGraceTime curto reduz o
tempo que uma conexão não autenticada segura recurso.
O X11Forwarding no fecha um encaminhamento que praticamente nenhum servidor
precisa e que, quando habilitado, permite a quem já está dentro alcançar a
interface gráfica de quem conectou. Pelo mesmo raciocínio, avalie AllowTcpForwarding
no — só que aqui vale conferir antes: é exatamente esse recurso que faz
funcionar o túnel para acessar um banco que só escuta em 127.0.0.1. Desligar sem
avisar quebra a rotina de quem depende dele, e o erro que aparece do outro lado
não menciona o servidor.
Aplicada a configuração, confirme o que ficou valendo de fato — o sshd combina
arquivos de vários lugares, e o valor efetivo nem sempre é o que você acabou de
escrever:
sudo sshd -T | grep -E 'passwordauthentication|permitrootlogin|allowgroups'Se você ainda está entrando com senha, o ponto de partida é trocar senha por chave: é o único item desta lista que muda a categoria do risco em vez de reduzir a margem. O resto é refino — e refino sobre senha exposta não protege ninguém.