Desenvolvimento de software
Ataques de tempo em PHP: Um exemplo prático - por que `hash_equals()` é importante
Você gostaria de ter um exemplo realista de um ataque de tempo aos tokens de API no Wordpress/Laravel/PHP? Abordamos esse assunto aqui, incluindo dicas e medidas de práticas recomendadas contra ataques de tempo.
Muitos desenvolvedores confiam na comparação simples usando === ou == ao verificar chaves de API, tokens ou outras cadeias de caracteres secretas. À primeira vista, isso parece razoável, mas há um problema: diferenças de tempo na comparação podem ser exploradas por invasores.
Este artigo descreve um exemplo realista de como um ataque de tempo funciona conceitualmente.
O cenário real (exemplo simplificado)
Imagine que um microsserviço interno aceita solicitações com um token de parâmetro de consulta e o compara com um token de API do GitHub armazenado no ambiente.
Código inseguro (simplificado):
$expected = getenv('GITHUB_API_TOKEN');$provided = $_GET['token'] ?? '';se ($provided === $expected) { } PHP
Explicarei por que isso é problemático na próxima seção.
Como funciona um ataque de tempo?
Se a implementação da comparação de tokens compara caractere por caractere e aborta imediatamente no primeiro erro, então uma solicitação com o primeiro caractere correto demora um pouco mais, em média.
Portanto, um primeiro caractere correto leva, em média, a um tempo de processamento um pouco mais longo do que um primeiro caractere incorreto. O mesmo se aplica ao segundo caractere e assim por diante.
Um invasor tira proveito disso testando todos os caracteres possíveis para cada posição, medindo os tempos de resposta com muita frequência e analisando-os estatisticamente. O caractere com o maior tempo médio/proporcionalmente mais longo provavelmente está correto. Dessa forma, o token é reconstruído passo a passo.
Por que hash_equals() é a escolha certa
O PHP fornece uma função de comparação de strings em tempo constante com hash_equals(). Ela garante que o tempo de execução da comparação não dependa de prefixos comuns, desde que as duas cadeias de caracteres tenham o mesmo comprimento.
Alternativa segura (para Laravel, PHP, Wordpress):
$expected = getenv('GITHUB_API_TOKEN'); $provided = $_GET['token'] ?? '';se (hash_equals($expected, $provided)) { } PHP
Observação: hash_equals() só é "independente do tempo" se os comprimentos forem iguais. É uma boa prática projetar tokens de modo que o comprimento seja constante (por exemplo, HMACs, UUIDs de comprimento fixo ou cadeias de caracteres Base64 aleatórias de comprimento fixo).
Você sabia? Somente o UUID-V4 é gerado de forma totalmente aleatória e, portanto, é usado com frequência para tokens de segurança. Como não contém informações relacionadas a tempo ou dispositivo, ele oferece um alto nível de imprevisibilidade e, portanto, protege contra ataques baseados em padrões ou previsões. É exatamente por isso que o UUID-V4 é a escolha preferida quando se trata de identificadores seguros e difíceis de adivinhar.
Medidas de defesa adicionais - mais do que apenas hash_equals()
- Comprimento constante do token
Use tokens com um comprimento fixo, por exemplo, UUID-V4. Se um invasor adivinhar o comprimento, isso será menos útil, desde que os caracteres em si sejam seguros.
- Limitação de taxa
Limite as solicitações por IP ou por conta. Os ataques de tempo exigem muitas medições; a limitação da taxa aumenta significativamente o esforço e os custos para o invasor.
- Registro e monitoramento
Reconheça padrões incomuns (muitas tentativas de token, variação sistemática de determinados parâmetros) e reaja automaticamente.
- Sal / HMAC / Assinaturas
Use tokens assinados (HMAC com chave secreta) ou tokens OAuth em vez de comparar abertamente chaves estáticas brutas.
- TLS/HTTPS
A criptografia protege os canais de comunicação - embora não impeça ataques de tempo aos componentes internos do servidor, é um requisito básico.
- Rotação de tokens
A vida útil curta dos tokens reduz o benefício de um token comprometido.
Conclusão
Os ataques de tempo não são um problema puramente teórico - eles foram investigados na prática e podem ter consequências graves, especialmente para pontos de extremidade acessíveis ao público. A boa notícia: para os desenvolvedores de PHP/Laravel/Wordpress, a primeira contramedida é muito simples:
- Substitua as comparações diretas de strings confidenciais por
hash_equals().
- Garanta comprimentos constantes de tokens, limitação de taxa, registro e gerenciamento seguro de tokens.