Verificação de Assinatura Webhook: Como Proteger Suas Integrações

Ashley Innocent

Ashley Innocent

22 dezembro 2025

Verificação de Assinatura Webhook: Como Proteger Suas Integrações

Webhooks são uma das formas mais poderosas de receber atualizações em tempo real de serviços de terceiros. Uma única requisição HTTP POST de Stripe, GitHub, Shopify ou Twilio pode acionar lógica de negócios crítica em sua aplicação — cobrando um cliente, atualizando um repositório, enviando um pedido ou mandando um SMS de confirmação.

Mas cada requisição de webhook chega pela internet pública. E isso significa que qualquer um que adivinhe ou descubra sua URL de webhook pode enviar payloads maliciosos que parecem completamente legítimos. Sem a autenticação adequada, sua aplicação não tem como diferenciar um evento real de um forjado.

É aí que entra a verificação de assinatura de webhook. É um mecanismo simples e padronizado que garante que cada requisição de webhook recebida seja genuinamente do serviço que você espera e que não tenha sido alterada durante o trânsito.

Neste guia abrangente, você aprenderá exatamente como funciona a verificação de assinatura de webhook e como implementá-la corretamente em linguagens populares. Você também verá erros comuns a serem evitados e como testar tudo de ponta a ponta — de forma rápida e confiável.

💡
Antes de entrarmos nos detalhes técnicos, quero ter certeza de que você tem a ferramenta certa para verificar e depurar webhooks em minutos. O Apidog é totalmente gratuito para download e oferece testes integrados de verificação de assinatura de webhook, servidores mock e inspeção de payload em tempo real — sem necessidade de cartão de crédito. É a maneira mais rápida de confirmar que sua lógica de verificação realmente funciona.
botão

O Que É Verificação de Assinatura de Webhook?

A verificação de assinatura de webhook é o processo de confirmar que uma requisição de webhook recebida realmente vem do serviço que você espera e que não foi adulterada.

A maioria dos provedores usa HMAC (Hash-based Message Authentication Code) com SHA-256 ou SHA-512. O serviço calcula:

signature = HMAC-SHA256(secret_key, payload)

Em seguida, eles enviam a assinatura em um cabeçalho (geralmente X-Signature, Signature ou X-Hub-Signature-256).

Seu servidor:

  1. Recebe o payload como bytes brutos (importante!)
  2. Recalcula o HMAC usando seu segredo armazenado
  3. Compara a assinatura calculada com a recebida

Se elas corresponderem exatamente, você processa o webhook. Caso contrário, você retorna HTTP 401 ou 403.

Por Que HMAC-SHA256 é o Padrão da Indústria

Os provedores escolhem HMAC-SHA256 por boas razões:

GitHub, Stripe, Shopify, Slack e dezenas de outros usam HMAC-SHA256.

Como Implementar Verificação de Assinatura de Webhook em Node.js

Vamos começar com um exemplo real em Node.js.

const crypto = require('crypto');

function verifyWebhookSignature(payload, signature, secret) {
  const hmac = crypto.createHmac('sha256', secret);
  const computedSignature = hmac.update(payload).digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(computedSignature),
    Buffer.from(signature)
  );
}

Pontos-chave a serem observados:

Exemplo de middleware Express:

app.post('/webhooks/stripe', (req, res, next) => {
  const signature = req.headers['stripe-signature'];
  const secret = process.env.STRIPE_WEBHOOK_SECRET;

  // Obter corpo bruto (Express precisa de middleware para preservar o corpo bruto)
  const rawBody = req.rawBody || req.body; // usar body-parser com a opção verify

  if (!verifyWebhookSignature(rawBody, signature, secret)) {
    return res.status(401).send('Invalid signature');
  }

  // A assinatura é válida → processar o evento
  next();
});

Implementação em Python (FastAPI + Pydantic)

from fastapi import FastAPI, Request, HTTPException
import hmac
import hashlib

app = FastAPI()

def verify_signature(payload: bytes, signature: str, secret: str) -> bool:
    computed = hmac.new(
        secret.encode(),
        payload,
        hashlib.sha256
    ).hexdigest()

    return hmac.compare_digest(computed, signature)

@app.post("/webhooks/github")
async def github_webhook(request: Request):
    signature = request.headers.get("X-Hub-Signature-256")
    if not signature:
        raise HTTPException(status_code=401, detail="Missing signature")

    payload = await request.body()

    if not verify_signature(payload, signature.split('=')[1], SECRET):
        raise HTTPException(status_code=401, detail="Invalid signature")

    # Processar webhook
    return {"status": "ok"}

Armadilhas Comuns Que Desenvolvedores Cometem (e Como Evitá-las)

1. Usando JSON.stringify() ou Corpo Parsed

Muitos frameworks analisam JSON automaticamente. Isso quebra a verificação porque espaços em branco, ordem das chaves e formatação diferem.

Solução: Sempre capture o corpo bruto antes de analisar.

No Express: Use body-parser com { verify: true }

No FastAPI: Use await request.body()

2. Comparando Strings com ===

Ataques de tempo podem vazar informações. Use crypto.timingSafeEqual ou hmac.compare_digest.

3. Armazenando Segredos no Código

Use variáveis de ambiente ou gerenciadores de segredos (AWS Secrets Manager, HashiCorp Vault, etc.).

4. Esquecer de Lidar com Ataques de Replay

A maioria dos provedores inclui um carimbo de data/hora. Verifique se o evento é recente (por exemplo, dentro de 5 minutos).

const timestamp = req.headers['X-Signature-Timestamp'];
if (Date.now() - timestamp > 5 * 60 * 1000) {
  return res.status(401).send('Timestamp too old');
}

5. Usando SHA-1 (Ainda Acontece!)

O GitHub descontinuou o SHA-1 em 2022. Sempre use SHA-256.

Testando a Verificação de Assinatura de Webhook com Apidog

Testar webhooks manualmente é doloroso. Você envia uma requisição, verifica os logs, corrige, repete.

O Apidog torna isso trivial:

No seu projeto Apidog, clique no ícone + na barra lateral esquerda e escolha "New Other Protocol APls" > "Webhook".

CleanShot 2025-11-05 at 17.18.02@2x.png

Após criar o Webhook, preencha os seguintes campos no editor:Método de Requisição: Tipicamente POST.Nome do Webhook: Isso aparecerá na documentação da API e na exportação OpenAPI, por exemplo, pedido.URL de Depuração (opcional): A URL real usada para enviar requisições de teste. *Nota: Isso é apenas para fins de teste e não será incluído na documentação*.Outras Informações: Como o corpo da requisição.

image.png

Clique em Salvar assim que tiver preenchido todos os campos obrigatórios.
Basta inserir sua URL de Webhook no campo URL de Depuração e, em seguida, clicar em Enviar para simular uma chamada de Webhook.

image.png

Eu economizei horas de depuração com o simulador de webhook do Apidog. Ele até suporta o formato exato stripe-signature do Stripe e o prefixo sha256=... do GitHub.

Exemplo do Mundo Real: Verificando Webhooks do Stripe

O Stripe usa um formato de cabeçalho especial:

stripe-signature: t=1681234567,v1=abc123...,v0=def456...

Você deve:

O Stripe fornece bibliotecas oficiais para lidar com essa complexidade:

const stripe = require('stripe')('sk_...');
stripe.webhooks.constructEvent(payload, sigHeader, endpointSecret);

Mas entender o HMAC subjacente é crucial quando você precisa implementá-lo por conta própria.

Tópicos Avançados: Tolerando Múltiplas Assinaturas

Alguns provedores (como o Stripe) enviam múltiplas assinaturas para compatibilidade retroativa. Seu código deve:

Melhores Práticas de Segurança em 2025

Conclusão: Pequeno Passo de Verificação, Grande Ganho de Segurança

A verificação de assinatura de webhook parece um pequeno detalhe. Mas é a diferença entre uma aplicação segura e uma que os atacantes podem explorar trivialmente.

Implemente-a corretamente, teste-a minuciosamente com ferramentas como o Apidog e durma melhor sabendo que suas integrações estão protegidas.

Baixe o Apidog gratuitamente hoje e verifique seu primeiro webhook em menos de 5 minutos. É a maneira mais rápida de provar que seu código realmente funciona.

botão

Pratique o design de API no Apidog

Descubra uma forma mais fácil de construir e usar APIs