Pular para o conteúdo principal
A segurança de webhooks é essencial para garantir que as requisições ao seu endpoint estejam de fato vindo do Firecrawl e não tenham sido adulteradas. Esta página mostra como verificar a autenticidade de webhooks e implementar as melhores práticas de segurança.

Por que a segurança de webhooks é importante

Sem a verificação adequada, invasores podem:
  • Enviar requisições de webhook falsas para disparar ações indesejadas
  • Modificar o payload para manipular sua aplicação
  • Sobrecarregar seu endpoint de webhook com requisições

Como o Firecrawl assina webhooks

O Firecrawl assina cada solicitação de webhook usando HMAC-SHA256 com a chave secreta da sua conta. Isso gera uma assinatura exclusiva para cada solicitação que comprova:
  1. Que a solicitação veio do Firecrawl
  2. Que o conteúdo não foi alterado

Encontrar sua chave secreta

Seu segredo de webhook está disponível na aba Advanced das configurações da sua conta. Cada conta tem um segredo exclusivo usado para assinar todas as solicitações de webhook.
Mantenha seu segredo de webhook em segurança e nunca o exponha publicamente. Se você acreditar que seu segredo foi comprometido, gere um novo imediatamente nas configurações da sua conta.

Verificação de assinatura

Como as assinaturas funcionam

Cada requisição de webhook inclui um cabeçalho X-Firecrawl-Signature neste formato:
X-Firecrawl-Signature: sha256=abc123def456...
A assinatura é calculada da seguinte forma:
  1. Use o corpo bruto da requisição (string JSON)
  2. Gere um hash HMAC-SHA256 usando sua chave secreta
  3. Converta para uma string hexadecimal
  4. Adicione o prefixo sha256=

Exemplos de implementação

import crypto from 'crypto';
import express from 'express';

const app = express();

// Use o parser de corpo bruto para verificar a assinatura
app.use('/webhook/firecrawl', express.raw({ type: 'application/json' }));

app.post('/webhook/firecrawl', (req, res) => {
  const signature = req.get('X-Firecrawl-Signature');
  const webhookSecret = process.env.FIRECRAWL_WEBHOOK_SECRET;
  
  if (!signature || !webhookSecret) {
    return res.status(401).send('Não autorizado');
  }
  
  // Extraia o hash do cabeçalho de assinatura
  const [algorithm, hash] = signature.split('=');
  if (algorithm !== 'sha256') {
    return res.status(401).send('Algoritmo de assinatura inválido');
  }
  
  // Calcule a assinatura esperada
  const expectedSignature = crypto
    .createHmac('sha256', webhookSecret)
    .update(req.body)
    .digest('hex');
  
  // Verifique a assinatura usando comparação com segurança temporal
  if (!crypto.timingSafeEqual(Buffer.from(hash, 'hex'), Buffer.from(expectedSignature, 'hex'))) {
    return res.status(401).send('Assinatura inválida');
  }
  
  // Analise e processe o webhook verificado
  const event = JSON.parse(req.body);
  console.log('Webhook do Firecrawl verificado:', event);
  
  res.status(200).send('ok');
});

app.listen(3000, () => console.log('Escutando na porta 3000'));

Verificação passo a passo

  1. Extraia a assinatura do cabeçalho X-Firecrawl-Signature
  2. Obtenha o corpo bruto da requisição exatamente como recebido (não faça parsing antes)
  3. Calcule o HMAC-SHA256 usando sua chave secreta e o corpo bruto
  4. Compare as assinaturas usando uma função de comparação segura a timing (timing-safe)
  5. Só processe o webhook se as assinaturas coincidirem

Práticas recomendadas de segurança

Sempre valide as assinaturas

Nunca confie em uma requisição de webhook sem verificar a assinatura:
// ❌ RUIM - Sem verificação
app.post('/webhook', (req, res) => {
  processWebhook(req.body); // Perigoso!
  res.status(200).send('OK');
});

// ✅ BOM - Verificado primeiro
app.post('/webhook', (req, res) => {
  if (!verifySignature(req)) {
    return res.status(401).send('Não autorizado');
  }
  processWebhook(req.body);
  res.status(200).send('OK');
});

Use comparações seguras em termos de tempo

Comparações padrão de strings podem revelar informações por tempo de execução. Use funções específicas:
  • Node.js: crypto.timingSafeEqual()
  • Python: hmac.compare_digest()
  • Outras linguagens: Procure funções de comparação “constant-time” ou “timing-safe”

Exigir HTTPS

Sempre use endpoints HTTPS para webhooks:
{
  "url": "https://your-app.com/webhook" // ✅ Seguro
}
{
  "url": "http://your-app.com/webhook" // ❌ Não seguro
}