Dev Tools

Como Validar Assinatura de Webhooks (HMAC SHA-256) com Segurança

Guia definitivo para validar assinaturas criptográficas de webhooks em Node.js e Python, prevenindo vulnerabilidades de timing attack e falsificação de requisições.

30 de outubro de 20267 min de leituraDevThru

Webhooks são a espinha dorsal da comunicação assíncrona na web moderna. Seja para receber notificações de pagamentos aprovados no Stripe, Asaas e Mercado Pago, eventos de repositório no GitHub ou mensagens no WhatsApp Cloud API, sua aplicação precisa expor um endpoint público HTTP na internet.

No entanto, expor uma rota pública traz um desafio crítico de segurança: como garantir que a requisição POST recebida foi genuinamente enviada pelo serviço terceiro e que o payload não foi forjado por um invasor? A resposta da indústria para esse desafio é o HMAC (Hash-based Message Authentication Code).

1. Como Funciona a Assinatura HMAC de Webhooks

O HMAC combina uma função de hash unidirecional (quase sempre SHA-256) com uma chave secreta compartilhada (Secret Key) que apenas o provedor e você possuem:

  1. No Provedor (ex: Stripe, GitHub): Ao disparar o evento, o servidor pega o corpo bruto da requisição (raw body) e calcula: HMAC-SHA256(raw_body, secret_key). O hash resultante é enviado em um cabeçalho HTTP (como Stripe-Signature ou X-Hub-Signature-256).
  2. No seu Servidor: Sua aplicação recebe a requisição, recalcula a mesma assinatura usando o corpo bruto e o segredo configurado no seu arquivo .env, e compara se a assinatura calculada é idêntica à assinatura do cabeçalho.

2. A Armadilha dos Timing Attacks (Ataques de Tempo)

O erro mais comum cometido por desenvolvedores ao implementar a verificação de assinatura é utilizar o operador clássico de igualdade de strings (if (receivedSignature === expectedSignature)).

Operadores de comparação padrão encerram a execução no primeiro caractere divergente. Isso significa que uma assinatura que acerta os primeiros 10 caracteres leva algumas frações de microssegundo a mais para ser rejeitada do que uma assinatura que erra logo no primeiro caractere. Invasores sofisticados utilizam essa variação de tempo para descobrir hashes válidos caractere por caractere (vulnerabilidade conhecida como Timing Attack).

Para evitar essa falha grave, as linguagens fornecem funções de comparação em tempo constante.

3. Implementação Segura em Node.js / TypeScript

No Node.js, utilize o módulo nativo node:crypto com a função crypto.timingSafeEqual. Atenção: nunca utilize o JSON já parseado; sempre utilize o buffer ou string exata do corpo bruto (raw body):

import crypto from "node:crypto";

export function verifyWebhook(
  rawBody: string,
  receivedSignature: string,
  secretKey: string
): boolean {
  // 1. Calcula o HMAC-SHA256 do corpo bruto
  const hmac = crypto.createHmac("sha256", secretKey);
  hmac.update(rawBody);
  const calculatedSignature = hmac.digest("hex");

  // 2. Prepara os buffers para comparação segura
  const receivedBuffer = Buffer.from(receivedSignature, "utf8");
  const calculatedBuffer = Buffer.from(calculatedSignature, "utf8");

  // 3. Verifica o tamanho dos buffers antes de comparar
  if (receivedBuffer.length !== calculatedBuffer.length) {
    return false;
  }

  // 4. Comparação em tempo constante contra Timing Attacks
  return crypto.timingSafeEqual(receivedBuffer, calculatedBuffer);
}

4. Implementação Segura em Python

No Python, a biblioteca padrão hmac possui a função hmac.compare_digest, desenvolvida especificamente para mitigar ataques de tempo:

import hmac
import hashlib

def verify_webhook(raw_payload: str, received_signature: str, secret_key: str) -> bool:
    # Calcula a assinatura esperada
    expected_signature = hmac.new(
        secret_key.encode('utf-8'),
        raw_payload.encode('utf-8'),
        hashlib.sha256
    ).hexdigest()

    # Comparação segura em tempo constante
    return hmac.compare_digest(expected_signature, received_signature)

5. Como Testar e Simular Assinaturas no Desenvolvimento

Durante a criação de testes locais ou simulações com cURL e Postman, você não precisa ficar disparando eventos reais no painel do gateway para gerar assinaturas de teste. Você pode utilizar o Gerador e Validador de HMAC Online do DevThru para calcular assinaturas instantaneamente em SHA-256 ou SHA-512 e testar a reação do seu webhook.

🛠️ Experimente na prática

Use nossas ferramentas online gratuitas — sem cadastro, direto no navegador.

WebhooksHMACSegurançaAPIsNode.jsPythonCriptografia

Esse artigo foi útil para você?