Webhooks Explicados: Payloads Assinados e Retentativas

Backend2026-10-09TryQuickToolBox

Você acabou de integrar um gateway de pagamento e agora precisa atualizar seu banco de dados quando um pagamento for bem-sucedido. Fazer polling na API a cada poucos segundos é desperdício e lento. Webhooks resolvem isso enviando eventos para o seu servidor conforme eles acontecem. Mas sem segurança e confiabilidade adequadas, webhooks podem se tornar uma fonte de bugs e vulnerabilidades. Este artigo explica como implementar webhooks corretamente, com foco em payloads assinados e retentativas.

O Que São Webhooks?

Um webhook é um callback HTTP: um evento ocorre em um serviço, e esse serviço envia uma requisição HTTP POST para uma URL que você fornece. O payload normalmente contém dados JSON sobre o evento. Por exemplo, quando um cliente conclui um pagamento, o Stripe envia um evento charge.succeeded para o seu endpoint.

Webhooks são baseados em push, então reduzem a latência e a carga do servidor em comparação com polling. No entanto, introduzem desafios: como você sabe que a requisição é genuína? E se o seu servidor estiver fora do ar quando o evento disparar?

Por Que Payloads Assinados Importam

Qualquer pessoa pode enviar um HTTP POST para o seu endpoint de webhook. Sem verificação, um atacante poderia forjar eventos, levando a ações não autorizadas, como marcar um pedido como pago. Payloads assinados resolvem isso incluindo uma assinatura criptográfica que apenas o remetente e você podem gerar.

O método mais comum é HMAC (Hash-based Message Authentication Code) com um segredo compartilhado. O remetente calcula um hash do payload usando o segredo e o inclui em um cabeçalho. Você recalcula o hash e compara. Se corresponderem, a requisição é autêntica.

Como Verificar um Payload Assinado

Aqui está uma abordagem passo a passo usando Node.js e Express:

  1. Recupere o corpo bruto da requisição como string. Não o analise como JSON antes da verificação, pois a análise pode alterar a sequência de bytes.
  2. Extraia a assinatura do cabeçalho (por exemplo, X-Signature).
  3. Calcule o HMAC usando seu segredo e o corpo bruto.
  4. Compare a assinatura calculada com a recebida usando uma comparação de tempo constante para evitar ataques de temporização.
const crypto = require('crypto');

function verifySignature(rawBody, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signature)
  );
}

app.post('/webhook', express.raw({type: 'application/json'}), (req, res) => {
  const signature = req.headers['x-signature'];
  if (!verifySignature(req.body, signature, process.env.WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }
  const event = JSON.parse(req.body);
  // Process event
  res.status(200).send('OK');
});

Sempre use um segredo forte e rotacione-o periodicamente. Nunca o exponha em código do lado do cliente.

Implementando Retentativas com Backoff

Webhooks são entregues pela internet, então falhas acontecem. Seu servidor pode estar fora do ar, ou a rede pode falhar. Um sistema de webhook robusto tenta novamente entregas falhas com backoff exponencial.

Normalmente, o remetente tenta novamente se não receber uma resposta 2xx dentro de um timeout (por exemplo, 5 segundos). O cronograma de retentativas pode ser: imediato, depois após 1 minuto, 5 minutos, 30 minutos, 2 horas, etc., até um número máximo de tentativas (por exemplo, 5).

Como receptor, você deve responder rapidamente para evitar timeouts. Confirme o recebimento com um 200 OK e processe o evento de forma assíncrona.

Lidando com Idempotência

Como as retentativas podem causar entregas duplicadas, o processamento do seu evento deve ser idempotente. Inclua um ID de evento único no payload e armazene os IDs processados. Antes de processar, verifique se o ID já foi tratado.

async function processEvent(event) {
  const { id, type, data } = event;
  if (await db.processedEvents.findOne({ id })) {
    return; // Already processed
  }
  await db.processedEvents.insertOne({ id });
  // Handle event based on type
}

Use uma transação de banco de dados para garantir que o evento seja marcado como processado somente após o tratamento bem-sucedido.

Melhores Práticas para Segurança de Webhooks

Comparação: Polling vs Webhooks

AspectoPollingWebhooks
LatênciaAlta (baseada em intervalo)Baixa (quase em tempo real)
Carga do ServidorAlta (requisições constantes)Baixa (apenas em eventos)
ComplexidadeSimples de implementarRequer segurança e retentativas
ConfiabilidadeDepende da frequência de pollingDepende da lógica de retentativa

FAQ

Como testar webhooks localmente?

Use uma ferramenta como ngrok para expor seu servidor local à internet. Configure o provedor de webhook para enviar eventos para sua URL do ngrok.

E se meu servidor estiver fora do ar quando um webhook for enviado?

O remetente deve tentar novamente com backoff. Garanta que seu servidor seja altamente disponível e responda rapidamente para evitar timeouts.

Posso usar assinaturas assimétricas em vez de HMAC?

Sim, alguns provedores usam assinaturas RSA ou ECDSA. Você verifica com a chave pública deles. HMAC é mais simples, mas requer um segredo compartilhado.

Ao depurar payloads de webhook, é útil formatar o JSON para facilitar a leitura. Experimente nosso JSON Formatter para formatar e validar payloads de webhook instantaneamente.