Webhooks Explicados: Payloads Assinados e Retries

Backend2026-11-02TryQuickToolBox

Por que webhooks precisam de assinaturas e retries

Você criou um endpoint para receber webhooks de um provedor de pagamentos ou plataforma SaaS. Tudo funciona nos testes, mas em produção você enfrenta dois problemas: como saber se a requisição realmente veio do provedor e o que acontece quando seu servidor está fora do ar ou lento? Sem payloads assinados, qualquer pessoa pode forjar uma requisição. Sem retries, uma única falha de rede pode perder um evento para sempre.

Este guia explica como implementar ambos corretamente. Abordaremos assinatura HMAC, etapas de verificação, estratégias de retry e idempotência — os três pilares do tratamento confiável de webhooks.

Como funcionam as assinaturas de webhook

Uma assinatura de webhook é um hash criptográfico que prova que o payload foi criado por alguém que conhece um segredo compartilhado. A maioria dos provedores usa HMAC-SHA256. O emissor calcula a assinatura sobre o corpo bruto da requisição (às vezes com um timestamp) e a inclui em um header. O receptor a recalcula e compara.

Eis um fluxo típico:

  1. Provedor e consumidor compartilham uma chave secreta (configurada no painel do provedor).
  2. O provedor cria o payload, calcula HMAC-SHA256(secret, payload) e o envia em um header como X-Signature.
  3. O consumidor recebe a requisição, lê o corpo bruto, recalcula o HMAC e compara usando uma função de tempo constante.
  4. Se coincidirem, processa o evento; caso contrário, rejeita com 401.

Importante: sempre use o corpo bruto da requisição como recebido, não uma versão parseada e re-serializada. A serialização JSON pode alterar espaços em branco e a ordem das chaves, quebrando a assinatura.

Adicionando timestamps para evitar ataques de replay

Um payload assinado sozinho pode ser reenviado por um atacante que captura uma requisição válida. Para mitigar, inclua um timestamp nos dados assinados e rejeite requisições com mais de alguns minutos. Por exemplo:

signed_payload = timestamp + "." + raw_body
signature = HMAC-SHA256(secret, signed_payload)

O consumidor verifica se o timestamp está dentro de uma janela aceitável (por exemplo, 5 minutos) e se a assinatura corresponde.

Implementando a verificação de assinatura

Vejamos um exemplo concreto em Python usando Flask. Vamos verificar uma assinatura enviada no header X-Signature.

import hmac
import hashlib
from flask import Flask, request, abort

app = Flask(__name__)
SECRET = b'your_shared_secret'

@app.route('/webhook', methods=['POST'])
def webhook():
    signature = request.headers.get('X-Signature')
    if not signature:
        abort(401)

    raw_body = request.get_data()
    expected = hmac.new(SECRET, raw_body, hashlib.sha256).hexdigest()

    if not hmac.compare_digest(expected, signature):
        abort(401)

    # Process the event
    event = request.json
    # ... handle event ...
    return '', 200

Pontos-chave:

Projetando uma estratégia de retry

Mesmo com assinaturas, webhooks podem falhar: seu servidor pode estar fora do ar, retornar um 500 ou atingir timeout. Os provedores normalmente fazem retry com backoff exponencial. Como consumidor, você também deve lidar com retries de forma elegante.

O que considerar:

A maioria dos provedores faz retry em respostas não-2xx ou timeouts, frequentemente por até 24 horas com intervalos crescentes. Consulte a documentação do seu provedor para detalhes.

Exemplo: handler de eventos idempotente

Use uma tabela no banco de dados para rastrear IDs de eventos processados. Eis um padrão simplificado:

def handle_event(event_id, payload):
    if db.exists('processed_events', event_id):
        return  # already handled
    # process payload
    db.insert('processed_events', event_id)
    # ... actual work ...

Para alto throughput, use uma restrição de unicidade no ID do evento e capture erros de chave duplicada.

Comparação: webhooks assinados vs. não assinados

AspectoPayloads assinadosPayloads não assinados
SegurançaVerifica a autenticidade do emissorQualquer pessoa pode forjar requisições
Proteção contra replayPossível com timestampsNenhuma
Esforço de implementaçãoModerado (HMAC + verificação de timestamp)Baixo
Recomendado paraTodos os webhooks de produçãoApenas testes internos

Armadilhas comuns e boas práticas

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 de uma fonte confiável e não foi adulterada.

Como lidar com retries de webhook sem duplicar ações?

Torne seu handler idempotente rastreando IDs de eventos. Antes de processar, verifique se o ID já foi tratado; se sim, retorne sucesso sem repetir o trabalho.

Posso usar webhooks sem assinaturas?

Não é recomendado para produção. Sem assinaturas, você não consegue distinguir requisições legítimas de forjadas. Sempre verifique assinaturas quando disponíveis.

Ao depurar payloads de webhook ou analisar logs de servidor, o JSON Formatter pode ajudar você a inspecionar e validar estruturas JSON rapidamente.