Criptografia na prática para devs: TLS, dados em repouso e hashing de senhas
Criptografia é uma daquelas áreas em que um pouco de conhecimento é perigoso. O desenvolvedor lê sobre AES, RSA e SHA, sente que entendeu, e parte para "proteger" os dados por conta própria. O resultado costuma ser um sistema que parece seguro, exibe cadeados e siglas, mas que um especialista quebra em minutos. A verdade desconfortável é que a maioria dos erros de criptografia não está no algoritmo, e sim em como ele é usado.
A boa notícia é que o dia a dia de um desenvolvedor não exige inventar criptografia. Exige tomar um punhado de decisões corretas e evitar um punhado de erros clássicos. Este guia foca exatamente nessas decisões práticas: como configurar TLS direito, como proteger dados em repouso, como fazer hashing de senhas do jeito certo e quais armadilhas nunca cruzar. Nada de matemática pesada, só as escolhas que aparecem no seu código.
A regra de ouro: não escreva sua própria criptografia
Antes de qualquer detalhe, o princípio que evita a maioria dos desastres: nunca implemente algoritmos criptográficos você mesmo. Criptografia é um campo em que erros sutis, invisíveis em testes funcionais, viram brechas graves. Os algoritmos padrão foram analisados por especialistas durante décadas; sua versão caseira não foi.
Na prática, isso significa usar bibliotecas consagradas e mantidas (a biblioteca de criptografia da plataforma, libsodium e equivalentes), e usar as funções de alto nível que elas oferecem, aquelas que escondem as decisões perigosas. "Criptografia caseira" inclui não só inventar um algoritmo, mas também combinar peças de baixo nível sem saber exatamente o que se faz. Se a sua solução depende de você escolher manualmente um modo de operação e um vetor de inicialização, provavelmente há uma função mais segura e mais simples que faz isso por você.
TLS: criptografia em trânsito bem configurada
TLS (o sucessor do SSL) protege os dados enquanto eles trafegam pela rede, garantindo confidencialidade e integridade entre cliente e servidor. Hoje, servir qualquer coisa sem TLS é indefensável. Mas "ter HTTPS" não é o fim da história; configurá-lo direito importa.
O que um desenvolvedor precisa garantir:
- TLS em todo lugar, sempre: inclusive em comunicação interna entre serviços. A ideia de que a rede interna é confiável é o oposto do Zero Trust.
- Versões modernas apenas: use TLS 1.2 e 1.3 e desabilite as versões antigas (SSL 3, TLS 1.0 e 1.1), que têm fraquezas conhecidas.
- HSTS: o cabeçalho
Strict-Transport-Securityobriga o navegador a só falar por HTTPS, fechando a janela para downgrade. - Certificados válidos e automatizados: use certificados de uma autoridade confiável e automatize a renovação (com ACME/Let's Encrypt, por exemplo), porque certificado expirado é uma causa banal e recorrente de indisponibilidade.
- Redirecionar HTTP para HTTPS: nenhuma rota sensível deve responder em texto claro.
A boa notícia é que ferramentas modernas de deploy e proxies reversos entregam uma configuração forte por padrão. O trabalho do time é não enfraquecê-la e verificar o resultado.
Dados em repouso: criptografar o que está guardado
Enquanto o TLS protege o dado em movimento, a criptografia em repouso protege o dado parado: no banco, em backups, em arquivos. O objetivo é que, se alguém obtiver acesso físico ao armazenamento ou roubar um backup, os dados não sejam legíveis.
Decisões práticas:
- Use a criptografia da plataforma: bancos, sistemas de arquivos e serviços de nuvem oferecem criptografia em repouso transparente. Ative-a. Resolve a maior parte dos casos com esforço mínimo.
- Criptografia em nível de aplicação para o mais sensível: dados especialmente críticos (documentos de identidade, dados de saúde, segredos) podem ser cifrados no nível da aplicação, antes de chegar ao banco, para uma camada extra.
- Escolha o algoritmo certo pela função certa: para cifrar dados, use AES em um modo autenticado como GCM, que garante confidencialidade e integridade. Prefira a função de alto nível da biblioteca a montar isso manualmente.
- A gestão de chaves é o ponto crítico: criptografia forte com a chave mal guardada não protege nada. As chaves vivem em um serviço de gestão de chaves (KMS) ou cofre, nunca no código, e são rotacionadas periodicamente.
Hashing de senhas: nunca criptografia, sempre hash
Aqui mora um dos erros mais comuns e mais graves. Senhas não devem ser criptografadas, porque criptografia é reversível: quem tem a chave recupera a senha. Senhas devem passar por hashing, um caminho de mão única do qual não se volta ao valor original. Na autenticação, você compara hashes, nunca recupera a senha.
E não é qualquer hash. Funções como MD5 ou SHA-256 puras são rápidas demais, o que as torna péssimas para senhas: um atacante testa bilhões por segundo. O que se usa são funções de hashing lentas e projetadas para senhas:
| Função | Característica | Recomendação |
|---|---|---|
| Argon2 | Vencedora da competição de hashing, resistente a ataques de GPU e de hardware | Preferência atual para novos sistemas |
| bcrypt | Consolidada, lenta por design, amplamente suportada | Ótima e segura opção madura |
| scrypt | Exige muita memória, dificultando ataques paralelos | Boa alternativa |
| MD5 / SHA puro | Rápidas, feitas para outra coisa | Nunca para senhas |
Dois detalhes que essas funções já tratam por você, e que você não deve tentar fazer à mão:
- Salt único por senha: um valor aleatório somado a cada senha impede que senhas iguais gerem o mesmo hash e derrota ataques de tabelas pré-computadas (rainbow tables). Argon2 e bcrypt geram e embutem o salt automaticamente.
- Fator de custo ajustável: essas funções permitem aumentar o esforço computacional conforme o hardware evolui, mantendo o hashing lento para o atacante ao longo dos anos.
A regra prática é curta: use Argon2 ou bcrypt, com os parâmetros recomendados, através da biblioteca. Não invente, não use SHA puro, não guarde senha em texto.
Os erros clássicos que você não pode cometer
Reunindo as armadilhas mais frequentes em uma lista de verificação mental:
- Criptografia caseira: já dito, mas é o mais grave. Não escreva a sua.
- Modo ECB: cifrar em blocos independentes (modo ECB) preserva padrões visíveis nos dados. Use sempre modos autenticados como GCM.
- Chaves e segredos no código: chave embutida no repositório é chave vazada. Cofre e KMS existem para isso.
- Reutilizar nonce ou IV: repetir o vetor de inicialização quebra garantias importantes de vários esquemas. Deixe a biblioteca gerá-lo.
- Criptografar senha em vez de fazer hash: senha se faz hash, com Argon2 ou bcrypt.
- Algoritmos obsoletos: MD5, SHA-1, DES e RC4 pertencem ao passado. Não os use para nada novo.
- Confiar em ofuscação: esconder não é cifrar. Base64 e "embaralhar" não protegem nada.
Criptografia é sobre decisões corretas, não sobre matemática
O desenvolvedor não precisa ser criptógrafo. Precisa, sim, tomar boas decisões: usar bibliotecas consagradas em vez de inventar, ligar TLS moderno em todo lugar, ativar a criptografia em repouso da plataforma, guardar chaves em um cofre e fazer hashing de senhas com Argon2 ou bcrypt. Evitados os erros clássicos, a maior parte do risco criptográfico desaparece. A segurança aqui não vem de complexidade, vem de disciplina e de humildade para usar o que já foi provado.
Na ConstructorTI, ajudamos times a acertar essas decisões e a encontrar onde elas foram erradas: revisão de configuração de TLS, avaliação de criptografia em repouso e gestão de chaves, auditoria de armazenamento de senhas e caça a criptografia caseira, segredos no código e algoritmos obsoletos. Se você quer garantir que os dados dos seus usuários estão de fato protegidos, e não apenas aparentemente, converse com o nosso time de CyberSecurity.