Hashes e salt para senhas em PHP: guia de segurança 2025

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Senhas na mira: por que métodos antigos não funcionam mais

\n

Imagine: você é um desenvolvedor criando um sistema de registro. Parece simples, não? Pegue a senha, passe pelo md5, salve no banco. Mas em 2025, essa abordagem é caminho direto para a vulnerabilidade. Ataques modernos, GPU-bruteforce e tabelas rainbow transformam hashes fracos em pó em segundos. A pergunta do Stack Overflow com milhares de visualizações — "Secure hash and salt for PHP passwords" — não perde relevância, e vamos resolvê-la de uma vez por todas.

\n

Neste artigo, você aprenderá como fazer hash de senhas corretamente em PHP, usando algoritmos modernos, funções nativas e salt. Adaptaremos as melhores respostas da comunidade para conteúdo educacional e mostraremos como proteger usuários mesmo em 2025.

\n\n

Por que md5 e sha1 são o mal

\n

Se você ainda usa md5 ou sha1 para armazenar senhas — pare. Esses algoritmos foram criados para velocidade, não para segurança. Em 2025, uma GPU pode gerar bilhões de hashes md5 por segundo. Adicionar salt (string aleatória) não salva: tabelas rainbow são contornadas, mas a velocidade continua fatal.

\n
    \n
  • Md5: 2^128 variações — quebrado em minutos.
  • \n
  • Sha1: um pouco melhor, mas também obsoleto.
  • \n
  • Salt sem lentidão: se o hash é rápido, o salt apenas adia o ataque.
  • \n
\n

Em vez disso, precisamos de algoritmos com "lentidão" — que exigem tempo e memória. É exatamente isso que o password_hash usa.

\n\n

password_hash e password_verify: solução nativa do PHP

\n

Desde o PHP 5.5, existem duas funções que resolvem 90% dos problemas de segurança de senhas: password_hash e password_verify. Elas geram automaticamente um salt criptograficamente seguro e usam algoritmos resistentes a bruteforce. Em 2025, este é o padrão, nada de soluções caseiras!

\n\n

Como funciona?

\n

A função password_hash recebe a senha e o algoritmo (padrão é bcrypt, mas pode usar argon2). Ela retorna uma string que já contém o salt e os parâmetros. Você não precisa armazenar o salt separadamente — ele está dentro do hash.

\n
<?php\n// Fazendo hash da senha\n$password = "SuperSecret123!";\n$hash = password_hash($password, PASSWORD_DEFAULT);\n\necho $hash; // $2y$10$... (60 caracteres)\n?>\n
\n

Agora, verificamos a senha no login:

\n
<?php\n$inputPassword = "SuperSecret123!";\n$storedHash = "$2y$10$..."; // do banco de dados\n\nif (password_verify($inputPassword, $storedHash)) {\n    echo "Senha correta!";\n} else {\n    echo "Senha incorreta.";\n}\n?>\n
\n

Simples e genial. O password_verify extrai automaticamente o salt do hash e verifica a senha. Nenhuma ação extra necessária.

\n\n

Escolha do algoritmo: bcrypt vs argon2

\n

Em 2025, você tem duas opções principais:

\n
    \n
  • Bcrypt (PASSWORD_BCRYPT): testado pelo tempo, usado por padrão. Resistente a ataques, mas requer configuração do cost factor.
  • \n
  • Argon2 (PASSWORD_ARGON2I ou PASSWORD_ARGON2ID): vencedor do Password Hashing Competition. Mais moderno, exige mais memória, dificultando ataques com GPU. Recomendado para novos projetos.
  • \n
\n

Exemplo com argon2:

\n
<?php\n$hash = password_hash($password, PASSWORD_ARGON2ID, [\n    'memory_cost' => 1 << 17, // 128 MB\n    'time_cost'   => 4,\n    'threads'     => 2\n]);\n?>\n
\n

O parâmetro memory_cost é a quantidade de memória em kilobytes. Quanto maior, mais seguro, porém mais lento. Para produção, teste no seu servidor.

\n\n

Salt: como funciona e por que não é necessário separadamente

\n

Muitos iniciantes perguntam: "Como adicionar salt manualmente?". Resposta: de jeito nenhum. O password_hash gera 22 caracteres de salt aleatório (para bcrypt

Blogs

Book Recommendations