Webhooks Explicados: Payloads Assinados e Retentativas
Você acabou de integrar um provedor de pagamento terceirizado. O usuário conclui uma compra, mas seu banco de dados nunca é atualizado. Por quê? Porque o webhook que deveria notificar seu aplicativo falhou silenciosamente. Sem verificação de assinatura e lógica de retentativa adequadas, os webhooks podem se tornar uma fonte de bugs misteriosos e vulnerabilidades de segurança.
Neste artigo, explicaremos como os webhooks funcionam, por que você deve verificar payloads assinados e como projetar um mecanismo de retentativa robusto. Também mostraremos como testar e depurar webhooks de forma eficaz.
O que são Webhooks?
Webhooks são callbacks HTTP definidos pelo usuário. Eles permitem que um sistema envie dados em tempo real para outro quando um evento ocorre. Por exemplo, quando um pagamento é processado, o provedor de pagamento envia uma requisição HTTP POST para uma URL que você especifica, contendo detalhes sobre o evento.
Diferente do polling, onde seu aplicativo pergunta repetidamente por atualizações, os webhooks enviam dados para você assim que estiverem disponíveis. Isso os torna eficientes e quase em tempo real.
O Problema de Segurança: Por que Verificar Assinaturas?
Endpoints de webhook são URLs publicamente acessíveis. Qualquer pessoa pode enviar uma requisição POST para eles. Sem verificação, um atacante poderia forjar uma requisição para, digamos, marcar um pedido como pago sem pagamento real. Para evitar isso, os provedores assinam cada payload com uma chave secreta.
Como Funcionam as Assinaturas HMAC
A maioria dos provedores usa HMAC (Hash-based Message Authentication Code) com SHA-256. Eles calculam um hash do corpo da requisição usando um segredo compartilhado e o incluem em um cabeçalho, como X-Signature. Seu servidor recalcula o hash e o compara com o cabeçalho. Se corresponderem, a requisição é autêntica.
Aqui está um exemplo simples em Python:
import hmac
import hashlib
def verify_signature(payload, secret, signature):
expected = hmac.new(secret.encode(), payload, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature)
Sempre use uma função de comparação de tempo constante como hmac.compare_digest para evitar ataques de temporização.
Erros Comuns a Evitar
- Usar o segredo errado: Cada ambiente (teste, produção) deve ter seu próprio segredo.
- Não verificar o timestamp: Alguns provedores incluem um timestamp para prevenir ataques de replay. Rejeite requisições mais antigas que alguns minutos.
- Registrar segredos em log: Nunca registre o segredo ou a assinatura completa em log na produção.
Projetando Retentativas Confiáveis
Webhooks são enviados pela internet, então falhas são inevitáveis. Redes caem, servidores reiniciam e endpoints expiram. Um bom sistema de webhook tenta novamente entregas falhas com backoff exponencial.
Como as Retentativas Normalmente Funcionam
Os provedores geralmente tentam novamente com atrasos crescentes: após 1 minuto, 5 minutos, 30 minutos, etc., até um número máximo de tentativas (por exemplo, 5-10). Se todas as retentativas falharem, o evento é marcado como falho e pode ficar disponível para replay manual.
Seu endpoint deve responder rapidamente com um código de status 2xx para confirmar o recebimento. Se você retornar um código não-2xx ou expirar, o provedor tentará novamente.
Implementando Idempotência
Como as retentativas podem causar entregas duplicadas, seu endpoint deve ser idempotente. Use o ID do evento (incluído no payload ou nos cabeçalhos) para rastrear eventos processados. Antes de processar, verifique se você já lidou com esse ID. Armazene IDs processados em um banco de dados com TTL.
Exemplo de verificação de idempotência:
def process_event(event_id, data):
if db.exists(f"processed:{event_id}"):
return # já processado
# processar dados
db.setex(f"processed:{event_id}", 86400, "1") # expira após 24h
Construindo um Receptor de Webhook: Passo a Passo
- Exponha um endpoint HTTPS: Use TLS para proteger os dados em trânsito.
- Verifique a assinatura: Rejeite requisições com assinaturas inválidas com um 401.
- Verifique o timestamp: Se fornecido, certifique-se de que está dentro de uma janela aceitável (por exemplo, 5 minutos).
- Analise o payload: Valide a estrutura JSON e os campos obrigatórios.
- Verifique a idempotência: Use o ID do evento para evitar duplicatas.
- Processe de forma assíncrona: Responda com 200 imediatamente e depois processe em um job em segundo plano para evitar timeouts.
- Registre e monitore: Registre falhas e configure alertas.
Testando Webhooks Localmente
Durante o desenvolvimento, você precisa de uma maneira de receber webhooks na sua máquina local. Ferramentas como ngrok ou localtunnel criam uma URL pública que encaminha para seu localhost. Alternativamente, muitos provedores oferecem uma CLI para disparar eventos de teste.
Sempre teste a verificação de assinatura com assinaturas válidas e inválidas. Simule retentativas retornando códigos de erro e observando o comportamento de retentativa do provedor.
Comparação: Webhooks vs. Polling
| Aspecto | Webhooks | Polling |
|---|---|---|
| Tempo real | Quase em tempo real | Atrasado pelo intervalo |
| Eficiência | Só envia dados quando o evento ocorre | Requisições frequentes mesmo sem dados |
| Complexidade | Requer endpoint, verificação de assinatura, retentativas | Mais simples de implementar |
| Confiabilidade | Depende do mecanismo de retentativa | Você controla o agendamento |
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 adulterada.
Quantas vezes um webhook deve ser retentado?
A maioria dos provedores tenta novamente 5-10 vezes com backoff exponencial. O número exato depende da política do provedor. Seu endpoint deve ser idempotente para lidar com duplicatas.
Qual código de status HTTP meu webhook deve retornar?
Retorne um código de status 2xx (por exemplo, 200 OK) para confirmar o recebimento bem-sucedido. Qualquer outro código (4xx ou 5xx) sinaliza falha e dispara retentativas.
Pronto para testar seus payloads de webhook? Use nosso JSON Formatter para validar e formatar payloads JSON rapidamente.