Pular para o conteúdo
11 min de leitura

Hardening de servidor Linux básico: do apt install ao servidor defensável

Compartilhar

Por Lucas Andrade ·

Um servidor recém-provisionado é uma porta aberta. Um roteiro prático e argumentado para transformar uma máquina Linux crua em algo que resiste ao primeiro scan da internet.

Neste artigo

Provisione uma VPS nova em qualquer provedor, dê a ela um IP público, e cronometre. Em minutos — não horas — os logs de autenticação já mostram tentativas de login por SSH vindas de dezenas de países. Não é ninguém mirando em você especificamente; é o ruído de fundo permanente da internet, botnets varrendo o espaço de endereços inteiro à procura de senha fraca, serviço desatualizado, porta esquecida aberta. Um servidor recém-instalado, com a configuração que veio de fábrica, é uma casa com a porta destrancada num bairro onde alguém testa cada maçaneta o tempo todo. Hardening é o trabalho de trancar as portas, tirar da rua o que não precisa estar exposto, e garantir que, se algo der errado, o estrago seja contido. Este artigo é um roteiro prático e argumentado — o porquê antes do como — para levar uma máquina Linux crua até um estado defensável.

O princípio que organiza tudo: superfície de ataque

Antes de qualquer comando, fixe o conceito que rege todas as decisões: superfície de ataque. Cada serviço que escuta numa porta, cada pacote instalado, cada usuário com shell, cada credencial no disco é uma via potencial de entrada. A matemática é implacável e libertadora ao mesmo tempo: menos coisa exposta, menos coisa para dar errado. Um serviço que não está rodando não tem vulnerabilidade explorável; uma porta que não está aberta não aceita conexão maliciosa. Portanto o primeiro instinto de hardening não é adicionar defesa, é remover superfície. Antes de instalar ferramenta de segurança, pergunte o que dá para desligar, desinstalar e fechar. Cada resposta afirmativa a essa pergunta vale mais do que qualquer camada extra sobre um sistema inflado.

Comece auditando o que a máquina expõe. Liste as portas em escuta com ss -tulpn e questione cada linha: esse serviço precisa mesmo estar acessível pela rede? O banco de dados, quase sempre, deveria escutar só em 127.0.0.1 ou num socket Unix, jamais no 0.0.0.0. O servidor de e-mail que veio junto com a imagem base, o rpcbind, o daemon de impressão — se você não os usa, eles não deveriam estar instalados. Remover pacote desnecessário com apt purge reduz superfície e reduz também o volume de atualizações que você terá de acompanhar. Servidor bom é servidor magro.

SSH: a porta da frente

SSH é, na esmagadora maioria dos casos, o único ponto de acesso administrativo, e por isso concentra a maior parte do esforço de endurecimento. A mudança mais importante, aquela que sozinha elimina classes inteiras de ataque, é abolir a autenticação por senha e usar exclusivamente chave pública. Senha pode ser adivinhada, vazada, reusada, arrancada por brute force; uma chave Ed25519 de 256 bits não é adivinhável na prática. Gere o par no seu cliente, instale a pública no servidor, e então, no sshd_config, defina PasswordAuthentication no e PubkeyAuthentication yes. A partir daí, todo o oceano de bots que tenta senha bate numa parede — eles não têm sua chave privada, e ponto.

Desative o login direto do root com PermitRootLogin no. Não é preciosismo: root é o alvo óbvio, o único usuário cujo nome o atacante sabe de antemão em qualquer Linux. Force o acesso a passar por um usuário nominal comum que depois eleva privilégio via sudo, e você ganha duas coisas — o atacante precisa acertar o nome do usuário além de possuir a chave, e cada ação privilegiada fica registrada e atribuível a uma pessoa. Considere também restringir quais usuários podem entrar por SSH com AllowUsers, transformando o acesso numa allowlist explícita em vez de um "todo mundo que existe no sistema".

Mudar a porta padrão do 22 para outra reduz drasticamente o ruído dos scans automatizados — não é segurança de verdade, é higiene de log, mas um log mais limpo torna mais fácil enxergar o ataque que importa. Complemente com fail2ban, que observa os logs de autenticação e bane temporariamente por firewall qualquer IP que erre repetidamente, sufocando brute force e reduzindo carga. E se a topologia permitir, restrinja o acesso SSH por origem: uma allowlist de IPs conhecidos, ou melhor ainda, exponha o SSH só através de uma VPN ou rede privada, tirando a porta administrativa da internet pública por completo.

Firewall: negar por padrão

O firewall codifica a decisão sobre superfície de ataque em regra viva. O princípio é deny-default de entrada: bloqueie todo tráfego de entrada e libere explicitamente apenas as portas que precisam estar abertas — tipicamente SSH e, num servidor web, 80 e 443. Tudo o mais fica fechado, de modo que um serviço acidentalmente exposto por má configuração não fica acessível de fora, porque o firewall nega antes que a conexão chegue nele. Essa é a rede de segurança que perdoa o erro humano.

Na prática, ufw é a interface amigável que basta para a maioria dos casos: definir política padrão de negar entrada, permitir a porta do SSH primeiro (não se tranque para fora!), permitir o que o serviço exige, e ativar. Por baixo dele está o nftables, que oferece controle fino quando você precisa de regras mais elaboradas — rate limiting por conexão, listas de bloqueio, NAT. O importante não é a ferramenta, é a postura: o padrão é fechado, a exceção é aberta e justificada. Saída também merece atenção em ambientes sensíveis — restringir o tráfego de saída dificulta a exfiltração e o call-home de um comprometimento —, mas comece pela entrada, que é onde o ataque bate primeiro.

Manter atualizado sem depender da memória

Vulnerabilidade conhecida com patch disponível e não aplicado é a causa mais banal e mais comum de servidor invadido. O intervalo entre a divulgação de uma falha e a varredura em massa por máquinas vulneráveis encolheu para horas. Depender de você lembrar de rodar apt upgrade é depender de algo que vai falhar num fim de semana ocupado. A resposta é automatizar as atualizações de segurança com unattended-upgrades, configurado para aplicar sozinho os patches do repositório de segurança e, quando necessário, reiniciar serviços ou agendar reboot. Sim, existe o risco de uma atualização quebrar algo; por isso você limita a automação ao canal de security e mantém ambientes de teste que recebem o patch antes da produção. O risco de automatizar é pequeno e gerenciável; o risco de ficar meses atrás do patch é uma questão de tempo até a invasão.

Usuários, sudo e menor privilégio

O princípio do menor privilégio diz que cada conta e cada processo deve ter exatamente as permissões de que precisa e nem uma a mais. Nada de login direto como root; cada operador tem sua conta nominal, e a elevação passa por sudo, que exige a senha do usuário, registra o que foi feito e pode ser restrito a comandos específicos. Um operador que só precisa reiniciar um serviço recebe uma regra de sudo para exatamente aquilo, não acesso irrestrito. Revise periodicamente quem tem acesso, remova contas de gente que saiu, e trate credencial como algo que se concede com parcimônia e se revoga sem cerimônia.

Serviços systemd hardened e isolamento por usuário

Aqui está uma das alavancas mais subestimadas do Linux moderno. O systemd oferece um arsenal de diretivas de sandboxing que confinam cada serviço com custo quase zero, e o padrão da casa é claro: cada serviço roda como seu próprio usuário Linux dedicado, num unit isolado e endurecido. A lógica é de contenção — se um serviço for comprometido, o atacante fica preso ao que aquele usuário e aquele sandbox permitem, sem alcançar os outros serviços nem o host. Dar um usuário próprio a cada processo (ou usar DynamicUser para criar um usuário efêmero por serviço) significa que comprometer o serviço web não dá acesso aos arquivos do serviço de faturamento; são identidades separadas, com arquivos e permissões separados.

Sobre esse alicerce, empilhe as diretivas de endurecimento no unit. NoNewPrivileges=yes impede que o processo ganhe privilégio via binários setuid, fechando um caminho clássico de escalada. ProtectSystem=strict monta todo o sistema de arquivos como somente-leitura para o serviço, deixando gravável apenas o que você declarar explicitamente. PrivateTmp=yes dá ao serviço um /tmp privado, isolando-o de ataques de link simbólico e de bisbilhotagem entre processos. Some ProtectHome, ProtectKernelTunables, RestrictAddressFamilies, capacidades removidas com CapabilityBoundingSet, e você transforma um serviço comum numa caixa apertada que, mesmo tomada, tem pouquíssimo para onde ir. É defesa em profundidade barata, declarativa e versionável junto do resto da configuração.

O sistema de arquivos somente-leitura merece destaque como princípio geral: onde a aplicação não precisa escrever, ela não deveria poder escrever. Código, binário e configuração idealmente ficam imutáveis em runtime; só os diretórios de dados e de estado são graváveis, e ainda assim com o mínimo de permissão.

Kernel, logs e segredos

Alguns ajustes de sysctl endurecem o kernel de graça: desabilitar redirecionamentos ICMP, ativar proteção contra SYN flood, habilitar rp_filter contra spoofing de origem, e garantir a randomização de layout de memória. São linhas de configuração que fecham vetores de rede e de exploração local com risco praticamente nulo de quebrar aplicação bem-comportada.

Log é o que permite descobrir que algo aconteceu — sem log, um comprometimento é invisível e a investigação é impossível. Mantenha os logs de autenticação e de sistema, configure rotação para não encher o disco (um servidor que trava por disco cheio de log é uma negação de serviço autoinfligida), e considere auditd para registrar eventos sensíveis: acesso a arquivos críticos, uso de comandos privilegiados, mudanças de configuração. Melhor ainda, envie os logs para fora da máquina — um atacante que ganha a máquina apaga os logs locais, mas não alcança o que já saiu para um coletor central.

Segredo nunca fica no disco em texto claro à toa. Senha de banco, chave de API, token de serviço não devem estar num arquivo .env legível por qualquer processo, nem hardcoded no código, nem no histórico do shell. Use um gerenciador de segredos, variáveis de ambiente injetadas em runtime com permissão restrita, ou arquivos com dono e modo estritos lidos só pelo usuário do serviço. E rode um scan atrás de segredo commitado por engano — vazamento de credencial no Git é uma das portas de entrada mais frequentes.

Servidor imutável, backup testado e monitoramento

Duas ideias fecham o roteiro e mudam a postura operacional inteira. A primeira é o servidor imutável: a máquina de produção não se edita à mão. Ninguém entra por SSH para consertar um arquivo de configuração ao vivo, porque isso cria drift — a divergência silenciosa entre o que está rodando e o que está versionado, que ninguém consegue reproduzir e que ninguém sabe explicar depois. O servidor recebe apenas artefato promovido a partir do Git, identificado por commit, através de um pipeline. Precisou mudar algo? Muda no repositório, testa, promove. O acesso de escrita direta ao servidor vira exceção auditada, break-glass, não rotina. Isso não é burocracia; é a diferença entre uma infraestrutura que você entende e reconstrói do zero e uma coleção de configurações mágicas que ninguém ousa tocar.

A segunda é o backup, com uma ressalva que vale ouro: backup que existe não é backup que funciona. Só existe backup de verdade aquele cujo restore você testou de ponta a ponta, recentemente, num ambiente separado. Incontáveis equipes descobriram no pior momento possível que o job de backup rodava havia meses gerando arquivos corrompidos, incompletos ou de uma base errada. Agende a restauração periódica como parte do processo, verifique que os dados voltam íntegros, e só então confie. E encerre com monitoramento: um servidor endurecido mas cego é metade do trabalho. Métricas de saúde, alertas sobre picos de falha de autenticação, sobre uso anômalo de CPU ou rede, sobre serviço fora do ar — a observabilidade é o que transforma um incidente silencioso num alerta acionável enquanto ainda dá tempo de reagir.

Conclusão

Hardening não é um produto que se instala, é uma postura que se aplica em camadas, e cada camada segue o mesmo fio condutor: reduza a superfície, negue por padrão, conceda o mínimo, contenha o comprometimento e mantenha a capacidade de enxergar e reagir. Feche o SSH atrás de chave e de um usuário nominal, ligue o firewall em deny-default, automatize os patches de segurança, isole cada serviço em seu próprio usuário e sandbox systemd, tire os segredos do disco em claro, trate o servidor como imutável alimentado pelo Git, e teste o backup até ter certeza de que ele restaura. Nenhum desses passos é heroico isoladamente; juntos, eles são a diferença entre uma máquina que cai no primeiro scan e um servidor que você pode deixar exposto à internet e dormir tranquilo.

Compartilhar

Compartilhar

Leituras relacionadas

Nenhum comentário ainda

Seja o primeiro a comentar.

Deixe seu comentário

Entre com sua conta Canverly para comentar. Você pode usar a mesma conta em qualquer site da rede.

Entrar com Canverly