Como Assinar Requisições de Webhook do Discord para Segurança
🔍 WiseChecker

Como Assinar Requisições de Webhook do Discord para Segurança

Webhooks do Discord permitem enviar mensagens automaticamente para canais. Mas sem verificação, qualquer pessoa que saiba sua URL pode enviar mensagens falsas. Isso pode levar a spam, phishing ou vazamento de dados. O Discord não assina requisições de webhook por padrão. Este artigo explica como adicionar uma assinatura às suas requisições de webhook para que seu servidor possa verificar que cada mensagem veio de você.

Principais Conclusões: Protegendo Webhooks do Discord com Requisições Assinadas

  • Assinatura HMAC-SHA256: Criptografa o corpo da requisição com uma chave secreta para provar autenticidade.
  • Cabeçalho X-Signature-Ed25519: Método alternativo usando criptografia de chave pública Ed25519 para interações assinadas.
  • Endpoint de verificação: Seu servidor verifica a assinatura antes de processar qualquer payload do webhook.

Por Que Assinar Requisições de Webhook do Discord é Importante

Uma URL de webhook do Discord é um endpoint HTTP simples. Qualquer pessoa que interceptar ou adivinhar essa URL pode enviar uma requisição POST com qualquer conteúdo. Seu bot ou aplicativo tratará como legítimo. Isso é uma falha de segurança. Assinar a requisição significa que seu remetente adiciona um hash criptográfico aos cabeçalhos HTTP. Seu receptor recalcula o hash usando uma chave secreta compartilhada. Se os hashes coincidirem, a requisição é autêntica. Se não coincidirem, a requisição é rejeitada.

Como Funciona a Verificação de Assinatura

O remetente calcula um hash HMAC-SHA256 do corpo da requisição usando uma chave secreta. O hash é colocado em um cabeçalho personalizado, geralmente X-Signature-256. O receptor lê o cabeçalho, calcula seu próprio HMAC-SHA256 do corpo com a mesma chave secreta e compara os dois. Uma comparação em tempo constante evita ataques de temporização. Este método funciona em qualquer linguagem de programação que suporte HMAC.

Alternativa: Assinaturas Ed25519

O próprio Discord usa assinaturas Ed25519 para seu Interactions Endpoint. Este é um sistema de chave pública. O remetente assina com uma chave privada. O receptor verifica com a chave pública correspondente. Para webhooks personalizados, você pode adotar o mesmo padrão. É mais seguro que HMAC porque a chave privada nunca sai do remetente. No entanto, requer mais configuração e uma biblioteca como nacl ou tweetnacl.

Passos para Assinar e Verificar Requisições de Webhook do Discord

Estes passos assumem que você controla tanto o remetente (seu aplicativo) quanto o receptor (outro servidor ou bot). Você precisa de uma chave secreta compartilhada. Gere uma string hexadecimal aleatória de 32 bytes. Mantenha-a em uma variável de ambiente segura em ambos os lados.

Método 1: Assinatura HMAC-SHA256 (Recomendado para a Maioria dos Usuários)

  1. Gere uma chave secreta compartilhada
    Execute openssl rand -hex 32 no seu terminal. Copie a saída. Esta é sua chave de assinatura.
  2. Crie a assinatura no lado do remetente
    Pegue o corpo bruto da requisição como string. Calcule HMAC-SHA256(chave, corpo). Converta o resultado para uma string hexadecimal. Adicione como cabeçalho: X-Signature-256: <string hex>.
  3. Envie a requisição do webhook
    Inclua o cabeçalho X-Signature-256 junto com a requisição POST para seu endpoint receptor.
  4. Verifique no lado do receptor
    Leia o cabeçalho X-Signature-256 da requisição recebida. Calcule HMAC-SHA256(chave, corpo) usando a mesma chave secreta. Compare as duas strings hexadecimais usando uma função de comparação em tempo constante. Se coincidirem, processe a requisição. Se não, retorne uma resposta 401 Unauthorized.

Método 2: Assinatura Ed25519 (Avançado)

  1. Gere um par de chaves Ed25519
    Use uma biblioteca como tweetnacl em Node.js ou PyNaCl em Python. Gere uma chave privada e uma chave pública. Armazene a chave privada no remetente. Compartilhe a chave pública com o receptor.
  2. Assine o corpo da requisição no remetente
    Assine a string do corpo bruto com a chave privada. Codifique a assinatura como string hexadecimal. Adicione como cabeçalho: X-Signature-Ed25519: <string hex>.
  3. Envie a requisição
    Inclua o cabeçalho X-Signature-Ed25519 com a requisição POST.
  4. Verifique no receptor
    Leia o cabeçalho. Use a chave pública para verificar a assinatura contra o corpo. Se a verificação for bem-sucedida, processe a requisição. Se falhar, rejeite-a.

Erros Comuns e Limitações

Incompatibilidade no Nome do Cabeçalho de Assinatura

Ambos os lados devem concordar com o nome exato do cabeçalho. Se o remetente usar X-Signature-256 mas o receptor esperar X-Signature, a verificação falha. Defina o nome do cabeçalho em sua documentação e aplique-o no código.

Diferenças na Codificação do Corpo

A assinatura é calculada a partir da sequência exata de bytes do corpo da requisição. Se o remetente incluir uma quebra de linha no final e o receptor não, os hashes serão diferentes. Use uma codificação consistente, como UTF-8 sem BOM, e evite alterações de espaços em branco.

Ataques de Temporização na Comparação

Nunca use um operador de igualdade simples para comparar strings HMAC. Isso permite que atacantes adivinhem a assinatura byte a byte. Use uma função de comparação em tempo constante fornecida pela sua linguagem. Em Python, use hmac.compare_digest. Em Node.js, use crypto.timingSafeEqual.

Exposição da Chave Secreta

Se sua chave secreta compartilhada vazar, qualquer pessoa pode forjar assinaturas. Rotacione a chave periodicamente. Armazene-a em um gerenciador de segredos ou variável de ambiente. Nunca a codifique diretamente no código-fonte.

HMAC-SHA256 vs Ed25519 para Assinatura de Webhook

Item HMAC-SHA256 Ed25519
Tipo de chave Simétrica (segredo compartilhado) Assimétrica (privada + pública)
Complexidade de configuração Baixa Média
Força de segurança Forte Mais forte (sem segredo compartilhado no receptor)
Rotação de chave Requer atualizar ambos os lados Apenas rotacionar chave privada
Suporte de bibliotecas Integrado na maioria das linguagens Requer biblioteca externa

Assinar suas requisições de webhook do Discord impede que remetentes não autorizados enviem mensagens falsas. Escolha HMAC-SHA256 pela simplicidade ou Ed25519 por segurança mais forte. Implemente comparação em tempo constante e rotacione sua chave secreta regularmente. Após assinar, teste a configuração enviando uma requisição com assinatura errada para confirmar que seu receptor a rejeita.