Aprofundamento

SSH — Secure Shell

SSH (Secure Shell) é o protocolo de acesso remoto cifrado que substituiu Telnet, rlogin e rsh — e, com SFTP e SCP, também o FTP em texto claro. Roda sobre TCP 22 e resolve três problemas de uma vez: prova ao cliente que o servidor é quem diz ser (chave de host), prova ao servidor quem é o usuário (senha, chave ou certificado) e cifra tudo o que passa depois. A versão em uso é a SSH-2 (RFC 4251 a 4254); a SSH-1 tem falha estrutural e está desativada há anos.

RFC 4251–4254 Transporte TCP 22 Camada Aplicação Substitui Telnet, rlogin, rsh, FTP Subsistemas SFTP, SCP Versão viva SSH-2

school O que o SSH garante

Duas autenticações, não uma

Toda sessão autentica os dois lados. O SERVIDOR se identifica pela chave de host, verificada contra o ~/.ssh/known_hosts do cliente. Só depois o USUÁRIO se identifica, por senha, chave pública ou certificado. Confundir as duas é a origem de metade das dúvidas: a mensagem sobre chave de host alterada não fala do seu login, fala da identidade da máquina.

Quem digita 'yes' sem olhar o fingerprint na primeira conexão abre mão justamente da proteção contra man-in-the-middle.

TOFU — confiança na primeira conexão

Sem uma CA, o SSH usa Trust On First Use: aceita a chave de host na primeira vez e a grava em known_hosts; a partir daí, qualquer mudança vira alerta. Isso protege da segunda conexão em diante, não da primeira. As saídas para fechar essa janela são registrar a chave por canal fora de banda, publicar registros SSHFP no DNS com DNSSEC, ou emitir certificados de host por uma CA SSH.

Em servidor reinstalado a chave muda de verdade. Apagar a linha antiga com 'ssh-keygen -R host' é correto; desligar a verificação com StrictHostKeyChecking=no é abrir mão dela para sempre.

Forward secrecy: a chave de host não cifra a sessão

A chave de host apenas ASSINA a negociação. As chaves de sessão nascem de uma troca Diffie-Hellman efêmera (hoje curve25519-sha256 ou os híbridos pós-quânticos do OpenSSH 9) e são descartadas ao fim. Por isso, capturar o tráfego hoje e roubar a chave de host amanhã não decifra o que foi gravado.

É a diferença entre 'a chave privada vazou' e 'todas as sessões passadas vazaram' — no SSH-2 a segunda não decorre da primeira.

Canais: uma conexão, várias coisas ao mesmo tempo

Depois da autenticação, a camada de conexão multiplexa canais dentro da mesma sessão TCP: o shell, uma transferência SFTP, um túnel de porta e um X11 podem coexistir. É o que permite ao ControlMaster reaproveitar uma conexão já aberta e abrir sessões novas em milissegundos, sem repetir o handshake.

É também por isso que 'só liberei SSH no firewall' não significa 'só liberei shell': túneis viajam dentro da mesma porta 22.

SSH-1 × SSH-2

A SSH-1 usa uma verificação de integridade por CRC-32 que permitiu o ataque de inserção conhecido como CRC compensation attack, e não separa as camadas de transporte e autenticação. Foi removida do OpenSSH; encontrar um serviço que ainda a ofereça é achado de auditoria, não curiosidade.

Nada de 'Protocol 2' no sshd_config moderno: a diretiva foi removida porque a SSH-1 não existe mais no código.

Certificados SSH: o known_hosts que não cresce

Uma CA SSH assina chaves de host e de usuário com validade e principals. O cliente confia em uma linha @cert-authority no known_hosts e passa a aceitar qualquer host assinado por ela; o servidor confia em TrustedUserCAKeys e passa a aceitar qualquer usuário com certificado válido, sem authorized_keys distribuído máquina a máquina.

Resolve os dois problemas operacionais do SSH em escala: a janela do TOFU e a revogação — certificado expira sozinho, chave em authorized_keys fica para sempre.

layers As três camadas do SSH-2

A separação em camadas é o que a SSH-1 não tinha. Cada uma entra em ação depois que a anterior terminou — e é por isso que um erro de autenticação já acontece dentro do túnel cifrado.

1 Transporte RFC 4253

Autentica o servidor, negocia algoritmos, faz a troca de chaves e passa a cifrar e verificar integridade de tudo.

Aqui se decidem cifra (chacha20-poly1305, aes-gcm), MAC, algoritmo de troca de chaves e algoritmo da chave de host. Também é onde a sessão renegocia chaves depois de volume ou tempo (RekeyLimit).

2 Autenticação do usuário RFC 4252

Prova quem é o usuário, já dentro do canal cifrado.

O servidor anuncia os métodos aceitos e o cliente tenta em ordem. Com AuthenticationMethods é possível EXIGIR mais de um (chave e depois TOTP), que é o 2FA real do SSH.

3 Conexão RFC 4254

Multiplexa canais: shell, exec, subsistema (SFTP), encaminhamento de porta e de X11.

Cada canal tem controle de fluxo próprio. É esta camada que torna possível ProxyJump, SOCKS dinâmico e reuso de conexão.

passkey Métodos de autenticação

Método Como funciona Avaliação Quando usar
publickey O cliente assina um desafio com a chave privada; o servidor confere com a pública do authorized_keys. A privada nunca sai da máquina do usuário. Recomendado Padrão para todo acesso administrativo. Combine com passphrase na chave e ssh-agent para não digitá-la a cada uso.
publickey com certificado A chave do usuário vem assinada por uma CA SSH, com validade e lista de principals. O servidor confia na CA, não em cada chave. Recomendado em escala Frota de servidores ou time com entrada e saída de pessoas: a validade curta resolve a revogação que authorized_keys não resolve.
keyboard-interactive Diálogo de perguntas e respostas conduzido pelo servidor, normalmente via PAM — é por onde entram TOTP e outros segundos fatores. Bom como segundo fator Junto com publickey em AuthenticationMethods, nunca como substituto dela.
password Senha enviada dentro do túnel cifrado e validada pelo sistema. Desaconselhado em servidor exposto Cifrada em trânsito, sim — mas é o que alimenta o volume de força bruta na porta 22. Em servidor com IP público, desligue.
hostbased A máquina cliente se autentica com a própria chave de host, e o servidor confia no nome de usuário que ela afirma. Uso restrito Cluster fechado e confiável. Fora disso, confiar na afirmação de identidade de outra máquina é premissa forte demais.
chave em hardware (FIDO2 / -sk) A chave privada mora numa YubiKey ou equivalente; o login exige toque físico no dispositivo. Mais forte Acesso a produção. Malware na estação não consegue exfiltrar a privada nem autenticar sem a presença física.

key Tipos de chave

Ed25519

Escolha padrão

Tamanho: 256 bits (fixo)

ssh-keygen -t ed25519 -C "paulo@estacao"

Ed25519-SK / ECDSA-SK

Melhor para produção

Tamanho: 256 bits + hardware

ssh-keygen -t ed25519-sk -O resident -O verify-required

RSA

Aceitável por compatibilidade

Tamanho: 3072 ou 4096 bits

ssh-keygen -t rsa -b 4096 -C "compatibilidade"

ECDSA (nistp256/384/521)

Evitar quando houver escolha

Tamanho: 256 a 521 bits

ssh-keygen -t ecdsa -b 521

DSA

Não usar

Tamanho: 1024 bits

Removido do OpenSSH — se aparecer em auditoria, é chave a substituir.

ssh-rsa (assinatura SHA-1)

Não usar

Tamanho: Independe do tamanho da chave

A chave RSA continua válida; o que se abandona é a assinatura SHA-1. Use rsa-sha2-256 ou rsa-sha2-512.

swap_calls Túneis e encaminhamentos

Liberar a porta 22 no firewall não libera apenas o shell: os túneis viajam dentro da mesma conexão. Por isso cada linha traz o cenário legítimo e o risco que carrega.

-L Encaminhamento local

Alcançar da sua máquina um serviço que só existe dentro da rede remota — um Postgres que escuta apenas em 127.0.0.1 no servidor.

ssh -L 5432:127.0.0.1:5432 paulo@servidor

Se usar 0.0.0.0 no lado local (GatewayPorts), qualquer um na sua rede alcança o banco remoto pela sua máquina.

-R Encaminhamento remoto

Expor no servidor um serviço que roda na sua máquina, para demonstração ou webhook.

ssh -R 8080:localhost:3000 paulo@servidor

É a técnica usada para criar canal de volta através de firewall. Onde não for necessário, desligue AllowTcpForwarding — inclusive para não virar ponte de saída de um invasor.

-D Proxy SOCKS dinâmico

Navegar com a origem da rede remota, sem VPN.

ssh -D 1080 paulo@servidor

Todo o tráfego do navegador passa a sair pelo servidor. Vale lembrar que a resolução DNS pode continuar local e vazar o destino.

-J ProxyJump

Chegar a uma máquina interna atravessando o bastion, sem manter chave no bastion.

ssh -J paulo@bastion paulo@interno

Praticamente nenhum — é justamente o substituto seguro do agent forwarding. A autenticação no destino acontece na sua estação.

-A Encaminhamento de agente

Usar sua chave a partir do servidor para chegar a um terceiro host.

ssh -A paulo@servidor   # prefira -J

Alto. Enquanto a sessão estiver aberta, quem for root no servidor intermediário fala com o socket do seu agente e se autentica como você em qualquer lugar. Se for inevitável, use ssh-add -c para exigir confirmação a cada uso.

-X / -Y Encaminhamento X11

Abrir aplicação gráfica remota na sua tela.

ssh -X paulo@servidor

-Y desliga as restrições de segurança do X e permite ao host remoto capturar teclas e telas. Mantenha X11Forwarding no no servidor quando não houver uso real.

lock Endurecimento do servidor

Diretivas do sshd_config. A coluna "se ficar aberto" existe para que a escolha seja consciente: cada linha aqui tem um custo operacional real.

Diretiva Valor Por quê Se ficar aberto
PermitRootLogin no (ou prohibit-password) Root é o único usuário cujo nome o atacante conhece de antemão em toda máquina Linux. Com 'yes' e senha habilitada, a força bruta tem alvo garantido e prêmio máximo.
PasswordAuthentication no Elimina de uma vez a força bruta e o vazamento por senha reaproveitada. Desligar sem antes TESTAR a chave em uma segunda sessão aberta é a forma clássica de se trancar do lado de fora.
KbdInteractiveAuthentication no Sem ela, desligar apenas PasswordAuthentication pode deixar a senha entrando pelo PAM assim mesmo. É o item esquecido que faz o servidor continuar aceitando senha depois de um endurecimento que parecia completo.
AuthenticationMethods publickey,keyboard-interactive A vírgula significa E, não OU: exige chave e depois o segundo fator. É o 2FA de verdade. Trocar a vírgula por espaço muda o significado para 'qualquer um dos dois' e desfaz a proteção sem nenhum aviso.
AllowUsers / AllowGroups AllowGroups sshusers Lista de permissão explícita: conta de serviço criada por um pacote não ganha acesso remoto de brinde. Sem ela, qualquer conta nova com shell válido passa a poder entrar pela rede.
LogLevel VERBOSE Registra o fingerprint da chave usada em cada login — sem isso, não há como saber QUAL chave entrou. Em INFO, a investigação de um acesso indevido termina em 'alguém autenticou com sucesso'.
AllowTcpForwarding / AllowAgentForwarding no (onde não houver uso) Corta o uso do servidor como ponte para a rede interna e o abuso do socket do agente. Servidor de acesso público com forwarding livre é pivô pronto para movimentação lateral.
MaxAuthTries / LoginGraceTime 3 / 20s Reduz tentativas por conexão e o tempo que uma sessão fica pendurada antes de autenticar. Grace time generoso somado a MaxStartups alto é vetor de esgotamento de recursos.
Ciphers / MACs / KexAlgorithms Apenas AEAD e curvas modernas Remove CBC e MACs legados e fecha o ataque Terrapin (CVE-2023-48795) quando o par não suporta strict kex. Fixar lista à mão envelhece: revise a cada atualização maior do OpenSSH em vez de copiar um guia antigo.
Restrições no authorized_keys command="...",no-port-forwarding,no-pty Uma chave de automação deve poder executar UM comando, não abrir shell. Chave de deploy sem restrição é chave de administração completa esperando ser copiada de um runner de CI.

science Laboratório

1. Gerar a chave e instalar no servidor

Primeiro acesso por chave, ainda com senha habilitada.

ssh-keygen -t ed25519 -C "paulo@estacao"
ssh-copy-id -i ~/.ssh/id_ed25519.pub paulo@servidor
ssh -i ~/.ssh/id_ed25519 paulo@servidor

ssh-copy-id acrescenta a chave ao authorized_keys com as permissões certas. Sem ele, lembre-se: ~/.ssh precisa ser 700 e authorized_keys 600, ou o StrictModes recusa em silêncio e o login volta a pedir senha.

2. Conferir o fingerprint antes de confiar

Primeira conexão a um servidor novo, fechando a janela do TOFU.

# no servidor, pelo console do provedor:
ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub

# na estação, comparar com o que o cliente mostrar:
ssh paulo@servidor

Os dois SHA256 têm de bater. Só então responder 'yes'. É o único momento em que a verificação depende do operador — depois disso o known_hosts faz o trabalho.

3. Endurecer o sshd sem se trancar do lado de fora

Desligar senha e root em um servidor de produção.

sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
sudo tee /etc/ssh/sshd_config.d/99-hardening.conf >/dev/null <<'EOF'
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
AllowGroups sshusers
LogLevel VERBOSE
EOF
sudo sshd -t && sudo systemctl reload ssh

A ordem importa: 'sshd -t' valida a sintaxe ANTES do reload, e o reload não derruba a sessão atual. Mantenha o terminal atual aberto e teste o login em uma segunda janela — se algo der errado, você ainda tem a sessão viva para desfazer.

4. Atravessar o bastion sem expor a chave

Máquina interna alcançável só pelo bastion.

# ~/.ssh/config
Host interno
  HostName 10.0.0.20
  User paulo
  ProxyJump paulo@bastion
  IdentityFile ~/.ssh/id_ed25519

Host *
  ControlMaster auto
  ControlPath ~/.ssh/cm-%r@%h:%p
  ControlPersist 10m

ProxyJump autentica no destino a partir da SUA estação — o bastion só encaminha bytes e nunca toca na sua chave, diferente do agent forwarding. O ControlMaster reaproveita a conexão e derruba o tempo dos acessos seguintes.

build Troubleshooting

Permission denied (publickey)

Causa provável Chave não oferecida, chave ausente do authorized_keys ou permissão de arquivo recusada pelo StrictModes.

ssh -vvv paulo@servidor 2>&1 | grep -i 'offering\|authentications that can continue'
sudo tail -n 50 /var/log/auth.log

Leitura No cliente, 'Offering public key' mostra o que foi tentado. No servidor, 'Authentication refused: bad ownership or modes' aponta permissão, não chave errada — ~/.ssh 700, authorized_keys 600 e o home não pode ser gravável pelo grupo.

WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED

Causa provável Servidor reinstalado, IP reaproveitado por outra máquina — ou, de fato, um man-in-the-middle.

ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub   # no servidor
ssh-keygen -R servidor                              # na estação, após confirmar

Leitura Confirme o fingerprint por um canal independente ANTES de remover a linha. Apagar por reflexo transforma um alerta de segurança em um clique de rotina.

Conexão trava depois do banner

Causa provável UseDNS fazendo resolução reversa lenta, ou MTU quebrada no caminho.

ssh -vvv paulo@servidor
sudo sshd -T | grep -i usedns

Leitura Se a pausa acontece entre 'SSH2_MSG_KEXINIT sent' e a resposta, suspeite de MTU/fragmentação. Se acontece após o banner e antes do prompt, é resolução reversa: UseDNS no.

Configuração alterada não surtiu efeito

Causa provável Diretiva sobrescrita por um arquivo em sshd_config.d ou por um bloco Match anterior.

sudo sshd -T | grep -i permitrootlogin
sudo sshd -T -C user=paulo,host=x,addr=203.0.113.9

Leitura 'sshd -T' imprime a configuração EFETIVA, que é o que vale — não o que está no arquivo que você editou. A forma com -C aplica os blocos Match para aquele usuário e origem.

Sessão cai sozinha após alguns minutos ociosa

Causa provável NAT ou firewall no caminho expirando a tradução da conexão ociosa.

# ~/.ssh/config
Host *
  ServerAliveInterval 30
  ServerAliveCountMax 3

Leitura ServerAliveInterval é do cliente e trafega dentro do túnel cifrado — diferente do TCPKeepAlive, que é do sistema e forjável. Do lado do servidor, o par é ClientAliveInterval.

Muitos logins falhos vindos da Internet

Causa provável Varredura automatizada na porta 22 — é o estado normal de qualquer IP público.

sudo grep -c 'Failed password' /var/log/auth.log
sudo fail2ban-client status sshd

Leitura Com PasswordAuthentication no, as tentativas viram ruído sem risco. O fail2ban reduz o volume de log e a carga; ele não substitui desligar a senha.

arrow_back Voltar ao catálogo de protocolos