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:
- Que a solicitação veio do Firecrawl
- 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:
- Use o corpo bruto da requisição (string JSON)
- Gere um hash HMAC-SHA256 usando sua chave secreta
- Converta para uma string hexadecimal
- 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
- Extraia a assinatura do cabeçalho
X-Firecrawl-Signature
- Obtenha o corpo bruto da requisição exatamente como recebido (não faça parsing antes)
- Calcule o HMAC-SHA256 usando sua chave secreta e o corpo bruto
- Compare as assinaturas usando uma função de comparação segura a timing (timing-safe)
- 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”
Sempre use endpoints HTTPS para webhooks:
{
"url": "https://your-app.com/webhook" // ✅ Seguro
}
{
"url": "http://your-app.com/webhook" // ❌ Não seguro
}