No ecossistema de pagamentos brasileiro, gateways como Mercado Pago e provedores de PIX assinam notificações de webhook com HMAC-SHA256: o lojista recebe uma chave secreta ao configurar a integração, e cada notificação recebida traz uma assinatura que precisa ser recalculada localmente e comparada com a recebida. Se a assinatura não bater, a notificação não veio de fato do provedor de pagamento — e não deve ser tratada como confirmação real de pagamento.
Por que é preciso uma chave secreta, não só um hash
Um hash comum como SHA-256 só prova que os dados não foram corrompidos em trânsito, não quem os enviou. Se um servidor apenas calculasse o hash do corpo do webhook e comparasse com um hash incluído na requisição, um invasor poderia forjar seu próprio payload falso e anexar um hash correspondente. O HMAC resolve isso misturando uma chave secreta que só o remetente e o destinatário conhecem — sem ela, produzir uma assinatura válida é inviável mesmo que o invasor saiba exatamente qual função hash está em uso.
Por que não é só "hash da chave mais a mensagem"
Concatenar ingenuamente a chave e a mensagem antes do hashing (por exemplo hash(chave + mensagem)) é vulnerável a ataques de extensão de comprimento em algumas funções hash — um invasor às vezes consegue anexar dados e calcular um novo hash válido sem conhecer a chave completa. O HMAC usa uma construção específica com hashing duplo e preenchimento interno/externo que fecha completamente essa classe de ataque.
Onde mais o HMAC aparece
Além de assinar webhooks, o HMAC autentica requisições de API e é a peça central do algoritmo TOTP — o mesmo que gera os códigos de seis dígitos em aplicativos autenticadores.
Para que serve
- Verificar a autenticidade de webhooks de gateways de pagamento ou outros serviços terceiros.
- Assinar requisições de API sem nunca enviar a chave secreta pela rede.
- Entender o funcionamento interno dos códigos TOTP e dos tokens de sessão.
Comparação em tempo constante
Comparar a assinatura recebida com a esperada usando um === simples é perigoso: esse operador geralmente para no primeiro byte de divergência, e o tempo da comparação revela ao invasor quantos bytes iniciais ele acertou. Um manipulador de webhook bem implementado sempre usa uma função de comparação em tempo constante — como hash_equals no PHP ou crypto.timingSafeEqual no Node.js — que verifica todos os bytes independentemente de onde está a primeira divergência.