Webhooks Explicados: Payloads Assinados e Retentativas

Backend2026-10-26TryQuickToolBox

Por que Webhooks Precisam de Payloads Assinados e Retentativas

Você acabou de integrar um serviço de terceiros que envia webhooks para o seu endpoint. Tudo funciona nos testes, mas em produção você percebe eventos perdidos, entregas duplicadas e, pior, alguém falsificando requisições para a URL do seu webhook. Sem medidas adequadas de segurança e confiabilidade, webhooks podem se tornar uma fonte de bugs e vulnerabilidades.

Webhooks são callbacks HTTP que notificam sua aplicação quando um evento ocorre. São simples em conceito, mas complicados na prática porque cruzam limites de confiança e problemas de confiabilidade de rede. Neste guia, abordaremos dois aspectos críticos: payloads assinados para verificar a autenticidade e retentativas para garantir a entrega. Vamos percorrer implementações práticas que você pode aplicar imediatamente.

Entendendo Payloads Assinados

Um payload assinado é uma forma de o remetente provar que o webhook veio dele e não foi adulterado. O remetente calcula uma assinatura criptográfica sobre o corpo da requisição (e às vezes cabeçalhos) usando um segredo compartilhado, e então inclui essa assinatura em um cabeçalho. Seu endpoint recalcula a assinatura e compara.

O algoritmo mais comum é HMAC-SHA256. É rápido, seguro e amplamente suportado. Veja como funciona:

  1. O remetente e o receptor compartilham uma chave secreta (configurada nas configurações do webhook).
  2. Para cada webhook, o remetente cria uma assinatura aplicando hash no payload com o segredo usando HMAC-SHA256.
  3. A assinatura é enviada em um cabeçalho como X-Signature.
  4. O receptor calcula o mesmo HMAC e compara usando uma comparação de tempo constante para prevenir ataques de temporização.

Implementando Verificação HMAC em Node.js

Vamos ver um exemplo concreto. Suponha que o remetente inclua a assinatura em X-Signature como uma string hexadecimal. Veja como verificá-la em uma rota Express:

const crypto = require('crypto');
const express = require('express');
const app = express();

// Use raw body for signature verification
app.use('/webhook', express.raw({ type: 'application/json' }));

app.post('/webhook', (req, res) => {
  const signature = req.headers['x-signature'];
  const secret = process.env.WEBHOOK_SECRET;

  const expected = crypto
    .createHmac('sha256', secret)
    .update(req.body)
    .digest('hex');

  if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
    return res.status(401).send('Invalid signature');
  }

  // Process the event
  const event = JSON.parse(req.body);
  console.log('Received event:', event.type);

  res.status(200).send('OK');
});

app.listen(3000);

Importante: Sempre use o corpo bruto da requisição para o cálculo da assinatura, não o JSON parseado. Parsear e re-stringificar pode alterar espaços em branco e ordenação, quebrando a assinatura.

Timestamp e Proteção contra Replay

Assinaturas sozinhas não previnem ataques de replay. Um atacante poderia capturar uma requisição assinada válida e reenviá-la depois. Para mitigar isso, inclua um timestamp no payload assinado ou em um cabeçalho. Por exemplo, adicione um cabeçalho X-Timestamp com o tempo Unix. O receptor verifica se o timestamp está dentro de uma janela de tolerância (ex.: 5 minutos) e rejeita requisições mais antigas.

Além disso, inclua o timestamp no cálculo da assinatura para prevenir adulteração. O remetente calcula HMAC sobre timestamp + '.' + body. O receptor faz o mesmo e compara.

Implementando Retentativas para Entrega Confiável

Webhooks trafegam pela internet pública, então falhas são inevitáveis: timeouts de rede, erros de servidor (5xx) ou seu endpoint temporariamente fora do ar. Um sistema de webhook robusto deve retentar entregas falhas.

Estratégias de Retentativa

Estratégias comuns de retentativa incluem:

Uma política típica pode ser: retentar até 5 vezes com backoff exponencial e jitter, começando em 10 segundos. Depois disso, marcar a entrega como falha e possivelmente alertar.

Idempotência: Lidando com Duplicatas

Retentativas podem causar entregas duplicadas. Seu endpoint deve ser idempotente—processar o mesmo evento duas vezes não deve causar efeitos colaterais como cobrar um cliente duas vezes. Inclua um ID de evento único no payload (ex.: event.id) e armazene IDs processados por um período razoável. Antes de processar, verifique se o ID já foi visto.

Alternativamente, projete suas operações para serem naturalmente idempotentes (ex.: usando upserts em vez de inserts).

Respondendo Rapidamente

Seu endpoint de webhook deve confirmar o recebimento rapidamente (dentro de alguns segundos) e processar o evento de forma assíncrona. Se o processamento demorar muito, o remetente pode dar timeout e retentar, causando duplicatas. Use uma fila: responda com 200 OK imediatamente após verificar a assinatura, então enfileire o evento para processamento em background.

Comparação de Medidas de Segurança para Webhooks

Medida Propósito Complexidade de Implementação
Assinatura HMAC Verificar autenticidade e integridade Baixa
Validação de timestamp Prevenir ataques de replay Baixa
Chaves de idempotência Evitar processamento duplicado Média
Allowlist de IP Restringir a IPs de remetentes conhecidos Baixa (mas frágil)
HTTPS Criptografar dados em trânsito Baixa

Embora a allowlist de IP possa adicionar uma camada, não é confiável porque os IPs do remetente podem mudar. Confie principalmente em assinaturas.

Testando Seu Endpoint de Webhook

Use ferramentas como ngrok para expor seu servidor local e disparar webhooks de teste a partir do painel do provedor. Verifique se as assinaturas são validadas corretamente e se as retentativas funcionam simulando falhas (ex.: retorne 500 nas primeiras tentativas).

Ao depurar, você pode precisar inspecionar payloads JSON. O JSON Formatter pode ajudar a formatar e validar payloads de webhook rapidamente.

FAQ

O que é um payload de webhook assinado?

Um payload assinado inclui uma assinatura criptográfica (geralmente HMAC) que permite ao receptor verificar que a requisição veio do remetente esperado e não foi alterada. É calculada usando um segredo compartilhado.

Quantas vezes devo retentar um webhook falho?

Não há um número universal, mas 3–5 retentativas com backoff exponencial são comuns. Depois disso, registre a falha e considere alertar. O objetivo é lidar com problemas transitórios sem retentativas infinitas.

Posso usar JWT para assinaturas de webhook?

Sim, alguns provedores usam JWT (JSON Web Tokens) para assinar webhooks. O token contém claims e é assinado com um segredo ou chave privada. A verificação é semelhante: valide a assinatura e verifique claims como expiração.

Pronto para implementar webhooks seguros? Comece gerando um segredo forte, adicionando verificação HMAC e configurando retentativas com idempotência. Para inspeção rápida de payloads durante o desenvolvimento, experimente nosso JSON Formatter para formatar e validar o JSON do webhook.