Se você já trabalhou com tokens, validações de login, APIs ou qualquer funcionalidade que envolva comparar valores sensíveis, provavelmente já fez algo como:

if ($tokenRecebido === $tokenArmazenado) {
    // Tudo certo!
}

Simples, né?
Só que existe um detalhe importante que quase ninguém comenta: esse tipo de comparação pode ser explorado por ataques de timing.

É aqui que entra o nosso herói discreto: hash_equals().

Ele parece uma função simples… e realmente é! Mas o que está por trás dela é muito valioso.

Hoje você vai entender, de forma clara e sem enrolação:

  • o que é hash_equals
  • por que ela é mais segura
  • quando e como usar
  • por que comparar strings pode se tornar um risco
  • exemplos práticos para usar no seu dia-a-dia
  • e em que momento você NÃO deve usar hash_equals (caso das senhas)

Vamos lá?

O que é hash_equals?

hash_equals() é uma função do PHP criada especificamente para comparar duas strings de forma segura, sem permitir que um atacante descubra diferenças entre elas medindo o tempo da comparação.

Comparações normais como === ou strcmp() param no primeiro caractere errado. Isso gera variações minúsculas no tempo de resposta que podem revelar pistas sobre qual parte da string está correta.

Essa técnica é chamada de ataque de timing.

O hash_equals() resolve isso.
Ele compara as duas strings sempre no mesmo tempo, independentemente de onde estiver a diferença.

Isso significa:

  • não vaza informações pelo tempo de execução
  • o atacante não consegue “adivinhar” partes da string
  • é a forma mais segura de comparar valores sensíveis

Simples e poderoso.

Onde usar hash_equals?

Use hash_equals() em qualquer situação onde o valor comparado é sensível, como:

  • tokens de API
  • tokens de validação em URLs
  • chaves de acesso internas
  • validação de webhooks
  • assinaturas digitais
  • qualquer valor secreto que não seja senha

Se é uma string sensível e precisa ser protegida contra ataques de timing, hash_equals é a melhor escolha.

Exemplo prático de uso

$tokenCorreto = 'ABC123XYZ';
$tokenRecebido = $_GET['token'] ?? '';

if (hash_equals($tokenCorreto, $tokenRecebido)) {
    echo "Token válido!";
} else {
    echo "Token inválido!";
}

Simples, seguro e eficiente.

Cuidados importantes ao usar hash_equals

hash_equals() exige que as duas strings tenham o mesmo tamanho.
Se o tamanho for diferente, ela retorna false e ainda gera um aviso no PHP.

Boa prática:

if (strlen($recebido) === strlen($correto) && hash_equals($correto, $recebido)) {
    // Sucesso
}

Assim você elimina warnings e mantém o padrão de segurança.

Quando NÃO usar hash_equals (senhas)

Um ponto fundamental:

hash_equals NÃO deve ser usado para validar senhas.

Muita gente comete esse erro porque pensa:
“Se é seguro para comparar strings, serve para comparar a senha digitada com o hash armazenado.”

Mas não serve.

  • Senhas devem ser tratadas de forma totalmente diferente, pois exigem:
  • algoritmos específicos para hashing de senhas
  • salts automáticos
  • proteção contra ataques de força bruta
  • rotinas de custo configurável
  • atualização automática para novos algoritmos

Por isso, a forma correta de trabalhar com senhas no PHP é:

Criar hash de senha:

$hash = password_hash($senhaDigitada, PASSWORD_DEFAULT);

Validar senha:

if (password_verify($senhaDigitada, $hash)) {
    echo "Senha correta!";
}

Simples assim.

O password_verify() faz um trabalho que vai MUITO além de uma comparação entre strings, então ele é a escolha obrigatória para qualquer fluxo de autenticação de usuários.

Se você quiser se aprofundar nesse tema e aprender passo a passo como usar password_hash e password_verify de forma correta, preparei um artigo completo sobre o assunto:
https://vivendodeprogramacao.com.br/php_password_hash_e_password_verify

Conclusão: um pequeno detalhe que traz muita segurança

O hash_equals() pode parecer uma função pequena, mas ela resolve um problema enorme.
Ao utilizá-la sempre que precisar comparar valores importantes, você evita brechas silenciosas que podem comprometer sua aplicação.

Sempre que lidar com:

  • tokens
  • assinaturas
  • chaves
  • códigos únicos
  • validações sensíveis

Use hash_equals().

 

Sempre que lidar com:

  • senhas

Use password_hash() e password_verify().

 

Saber essa diferença demonstra que você domina boas práticas de segurança e escreve código profissional — mesmo sendo iniciante.