A Regra Zero: Nunca Armazene a Senha
O princípio fundamental da segurança de senhas é contraintuitivo para iniciantes: você nunca deve armazenar a senha do usuário. Nem em texto puro, nem cifrada de forma reversível. O que você armazena é o hash da senha — uma transformação unidirecional da qual a senha original não pode ser recuperada. Quando o usuário faz login, você aplica a mesma transformação na senha digitada e compara os hashes. Se baterem, a senha está correta, e em nenhum momento você precisou saber qual era a senha de verdade.
Por que isso importa tanto? Porque vazamentos de banco de dados acontecem — por falha de configuração, SQL injection, credencial comprometida, funcionário mal-intencionado. Se o seu banco guarda senhas em texto puro, um vazamento expõe instantaneamente todas as senhas dos seus usuários. E como as pessoas reutilizam senhas, você acabou de entregar acesso ao e-mail, banco e redes sociais delas. Armazenar apenas o hash transforma um vazamento catastrófico em um incidente gerenciável.
Os Três Pilares de um Armazenamento Responsável
1. Algoritmo de hash apropriado para senhas
Não é qualquer hash que serve. Hashes de propósito geral como MD5, SHA-1 e até SHA-256 são rápidos demais — projetados para calcular checksums de arquivos em alta velocidade. Essa velocidade é fatal para senhas: um atacante com uma GPU calcula bilhões de tentativas por segundo. Para senhas, use funções de derivação deliberadamente lentas e com uso de memória: Argon2id (recomendação atual do OWASP), BCrypt ou scrypt. Elas tornam cada tentativa custosa, inviabilizando a força bruta mesmo após um vazamento.
2. Salt único por senha
O salt é um valor aleatório, único para cada usuário, combinado com a senha antes do hash. Ele resolve dois problemas: impede ataques de rainbow table (tabelas pré-computadas de hashes comuns) e garante que dois usuários com a mesma senha tenham hashes diferentes. A boa notícia é que algoritmos modernos como Argon2id e BCrypt geram e embutem o salt automaticamente na string de resultado — você não precisa gerenciá-lo manualmente. Cada hash já vem com seu próprio salt único.
3. Custo calibrado ao seu hardware
O que torna esses algoritmos seguros é o custo computacional, e ele é configurável. No Argon2id você ajusta memória, iterações e paralelismo; no BCrypt, o cost factor. A regra do OWASP é calibrar para que cada operação de hash leve pelo menos um segundo no seu servidor de produção. E como o hardware fica mais rápido com o tempo, esses parâmetros devem ser revisados periodicamente — o que era seguro há cinco anos pode estar fraco hoje.
O Padrão de Implementação Correto
Em PHP, o ecossistema oferece tudo pronto e seguro por padrão. A função password_hash() com PASSWORD_ARGON2ID (ou PASSWORD_BCRYPT) gera o hash com salt embutido e parâmetros configuráveis. A verificação no login usa password_verify(), que extrai o salt e os parâmetros do próprio hash armazenado e faz a comparação de forma segura contra ataques de timing. E password_needs_rehash() permite atualizar hashes antigos para parâmetros mais fortes de forma transparente, no momento do login. Esse trio cobre o ciclo completo sem você precisar tocar em criptografia de baixo nível — onde, aliás, é onde a maioria dos erros acontece.
A lição prática aqui é: nunca implemente o hashing de senha você mesmo a partir do zero. Use as funções da plataforma. Elas foram auditadas, tratam o salt, resistem a timing attacks e seguem as recomendações atuais. Criptografia caseira é uma das maiores fontes de vulnerabilidade em aplicações web.
Experimente e Entenda na Prática
Para ver como um hash de senha responsável se parece, use o Gerador Argon2id: gere o hash de uma senha e observe a string de resultado, que já contém o algoritmo, os parâmetros (memória, iterações, paralelismo) e o salt embutidos — tudo o que password_verify() precisa para validar depois. A ferramenta também permite verificar uma senha contra um hash existente, demonstrando exatamente o fluxo de login seguro. Ver os parâmetros explícitos no resultado deixa tangível por que esse formato é autossuficiente e seguro.
Erros que Ainda São Comuns
Apesar de tudo ser conhecido há anos, os mesmos erros se repetem: armazenar senha em texto puro "temporariamente" (e nunca corrigir), usar MD5 ou SHA-1 por hábito ou por copiar código antigo, implementar salt global em vez de salt por usuário, aplicar SHA-256 puro achando que "hash é hash", e enviar a senha por e-mail em texto puro na recuperação de conta (se você consegue enviar a senha, é porque a armazenou de forma reversível — sinal de problema grave). Reconhecer esses antipadrões é metade do caminho para não cometê-los.
Migração: Como Sair de um Algoritmo Fraco sem Pedir a Senha
Uma dúvida frequente é como migrar de um esquema fraco — senhas em MD5, SHA-1 ou SHA-256 puro — para um algoritmo moderno, já que você não conhece as senhas dos usuários. A resposta é o padrão de rehash no login. Quando o usuário autentica com sucesso usando o hash antigo, você tem, naquele instante, a senha em texto puro que ele acabou de digitar. Aproveite esse momento: gere imediatamente um novo hash com Argon2id ou BCrypt a partir dessa senha e substitua o registro antigo no banco. O usuário nem percebe; na próxima vez, ele já será validado pelo algoritmo forte.
Em algumas semanas, a maior parte da sua base ativa terá migrado naturalmente, conforme as pessoas fazem login. Para os usuários inativos que restarem com hash antigo, a estratégia segura é forçar uma redefinição de senha na próxima vez que tentarem entrar, ou em uma data limite. Uma técnica intermediária para acelerar a proteção é envelopar o hash fraco existente dentro de um hash forte (por exemplo, aplicar BCrypt sobre o SHA-256 já armazenado), o que protege imediatamente todos os registros sem esperar o login — embora exija ajustar a lógica de verificação para aplicar as duas camadas.
Senhas Comprometidas e Políticas Sensatas
Armazenar bem é metade do trabalho; incentivar boas senhas é a outra. As recomendações atuais (como as do NIST) viraram do avesso a sabedoria antiga: o que protege não é forçar trocas periódicas nem exigir aquela combinação artificial de maiúscula, número e símbolo — regras que levam os usuários a senhas previsíveis como "Senha@2026". O que realmente protege é o comprimento (frases longas são exponencialmente mais difíceis de quebrar), a verificação contra listas de senhas já vazadas (impedindo que alguém reutilize uma senha que já está em bancos de dados de vazamentos conhecidos), e o uso de autenticação de dois fatores. Permita senhas longas, não force complexidade artificial, bloqueie senhas sabidamente comprometidas, e você terá um sistema de autenticação muito mais resistente do que o das regras tradicionais.
Perguntas Frequentes
Preciso gerenciar o salt manualmente?
Não, e não deveria. Algoritmos modernos como Argon2id e BCrypt geram um salt aleatório único automaticamente e o embutem na própria string do hash. Quando você usa password_hash() em PHP, o salt é criado e armazenado junto com o resultado; quando você chama password_verify(), ele extrai o salt do hash automaticamente. Gerenciar salt manualmente é desnecessário e propenso a erro. Deixe a função da plataforma cuidar disso.
Posso recuperar a senha original a partir do hash?
Não, e esse é exatamente o objetivo. O hash é unidirecional por design — não existe operação de "des-hash". É por isso que aplicações responsáveis oferecem redefinição de senha (você cria uma nova) em vez de recuperação (mostrar a antiga). Se um serviço consegue lhe enviar sua senha atual por e-mail, isso significa que ele a armazenou de forma reversível ou em texto puro, o que é uma falha grave de segurança. Recuperação que mostra a senha é um sinal de alerta.
Hash de senha é suficiente, ou preciso de mais camadas?
Hash correto é a base indispensável, mas segurança é em camadas. Some a ele: autenticação de dois fatores (2FA), que protege mesmo se a senha vazar; limitação de tentativas de login (rate limiting) contra força bruta online; políticas de senha que incentivem senhas longas; e monitoramento de vazamentos conhecidos. O hash protege as senhas em repouso no banco; as outras camadas protegem o processo de autenticação como um todo. Juntas, elas formam uma defesa robusta.