Webhooks Explicados: Payloads Assinados e Retentativas
Você acabou de integrar o webhook de um provedor de pagamentos para receber atualizações de transações. Tudo funciona nos testes, mas em produção você percebe eventos ausentes durante picos de tráfego ou cobranças duplicadas quando o provedor tenta novamente. Webhooks são simples em conceito, mas complicados na prática: eles cruzam limites de rede, podem ser atrasados, duplicados ou falsificados. Este artigo explica como construir consumidores e produtores de webhooks robustos usando payloads assinados e estratégias inteligentes de retentativa.
O que são Webhooks?
Webhooks são callbacks HTTP definidos pelo usuário, acionados por eventos. Quando algo acontece em um sistema de origem (por exemplo, um novo pedido), ele envia uma requisição HTTP POST para uma URL que você fornece. Diferente do polling, os webhooks enviam dados quase em tempo real, reduzindo a latência e a carga no servidor.
No entanto, webhooks introduzem desafios: garantir que a requisição realmente veio do remetente esperado, lidar com falhas de forma elegante e evitar processamento duplicado.
Protegendo Webhooks com Payloads Assinados
Sem verificação, qualquer pessoa pode enviar requisições falsas para o seu endpoint de webhook. Payloads assinados resolvem isso incluindo uma assinatura criptográfica que você pode validar.
Como funcionam as assinaturas HMAC
O remetente calcula um código de autenticação de mensagem baseado em hash (HMAC) usando um segredo compartilhado e o corpo da requisição. A assinatura é enviada em um cabeçalho (por exemplo, X-Signature). Você recalcula o HMAC do seu lado e compara.
// Exemplo em Node.js: verificando a assinatura de um webhook
const crypto = require('crypto');
function verifySignature(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
Sempre use uma função de comparação de tempo constante como timingSafeEqual para prevenir ataques de temporização.
Inclua um Timestamp
Para prevenir ataques de replay, inclua um timestamp no payload assinado e rejeite requisições mais antigas que alguns minutos (por exemplo, 5 minutos). O timestamp deve fazer parte dos dados assinados.
Implementando Retentativas Confiáveis
Problemas de rede ou erros temporários no servidor podem fazer com que a entrega do webhook falhe. Um remetente robusto tenta novamente entregas falhas com backoff exponencial.
Estratégia de Retentativa
- Backoff exponencial: Espere mais tempo entre cada tentativa (por exemplo, 1s, 2s, 4s, 8s...).
- Máximo de tentativas: Defina um limite (por exemplo, 5 tentativas) para evitar loops infinitos.
- Fila de mensagens mortas: Após o máximo de tentativas, armazene o evento para inspeção manual.
- Idempotência: Inclua um ID de evento único para que o receptor possa deduplicar.
Exemplo: Retentativa com Backoff em Python
import time
import requests
from requests.exceptions import RequestException
def send_webhook(url, payload, max_retries=5):
for attempt in range(max_retries):
try:
response = requests.post(url, json=payload, timeout=5)
if response.status_code < 500:
return True # sucesso ou erro do cliente (sem retentativa)
except RequestException:
pass
time.sleep(2 ** attempt) # backoff exponencial
return False
Melhores Práticas para Consumidores de Webhooks
- Responda rapidamente: Confirme o recebimento com um status 2xx antes de processar. Enfileire o trabalho de forma assíncrona.
- Valide assinaturas: Sempre verifique a assinatura antes de confiar no payload.
- Lide com duplicatas: Use o ID do evento para garantir processamento idempotente.
- Registre tudo: Mantenha logs dos webhooks recebidos para depuração.
Comparação: Webhooks vs Polling
| Aspecto | Webhooks | Polling |
|---|---|---|
| Latência | Quase em tempo real | Depende do intervalo |
| Carga no servidor | Baixa (apenas push) | Alta (requisições frequentes) |
| Complexidade | Maior (precisa de endpoint, segurança) | Menor |
| Confiabilidade | Requer retentativas | Retentativa inerente |
Perguntas Frequentes
O que é um payload de webhook assinado?
Um payload assinado inclui uma assinatura criptográfica (geralmente HMAC) que permite ao receptor verificar a autenticidade e integridade da requisição.
Quantas vezes devo tentar novamente um webhook que falhou?
Uma prática comum é de 3 a 5 retentativas com backoff exponencial, mas depende do seu SLA e da criticidade do evento.
Posso usar webhooks sem HTTPS?
Não, sempre use HTTPS para proteger o payload e a assinatura contra interceptação. HTTP simples expõe dados sensíveis.
Ao depurar payloads de webhooks, você pode precisar formatar JSON rapidamente. Experimente nosso JSON Formatter para formatar e validar respostas JSON.