> ## Documentation Index
> Fetch the complete documentation index at: https://docs.firecrawl.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Seguridad

> Verificar la autenticidad de los webhooks

Verifica que cada solicitud de webhook provenga realmente de Firecrawl comprobando su firma HMAC-SHA256. Esto evita que los atacantes falsifiquen la carga útil y te permite confiar en los datos antes de actuar en consecuencia.

<div id="secret-key">
  ## Clave secreta
</div>

Tu secreto de webhook está disponible en la [pestaña Advanced](https://www.firecrawl.dev/app/settings?tab=advanced) de la configuración de tu cuenta. Cada cuenta tiene un secreto único que se utiliza para firmar todas las solicitudes de webhook.

<Warning>
  Mantén tu secreto de webhook seguro y nunca lo expongas públicamente. Si crees que tu secreto se ha visto comprometido, regénéralo de inmediato desde la configuración de tu cuenta.
</Warning>

<div id="signature-verification">
  ## Verificación de firmas
</div>

Cada solicitud de webhook incluye un encabezado `X-Firecrawl-Signature`:

```
X-Firecrawl-Signature: sha256=abc123def456...
```

<div id="how-to-verify">
  ### Cómo verificar
</div>

1. Extrae la firma del encabezado `X-Firecrawl-Signature`
2. Obtén el cuerpo sin procesar de la solicitud (antes de analizarlo)
3. Calcula el HMAC-SHA256 usando tu clave secreta
4. Compara las firmas usando una función de comparación segura frente al tiempo

<div id="implementation">
  ### Implementación
</div>

<CodeGroup>
  ```js Node/Express theme={null}
  import crypto from 'crypto';
  import express from 'express';

  const app = express();

  // Usa el analizador de cuerpo en bruto para verificar la firma
  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('No autorizado');
    }
    
    // Extrae el hash del encabezado de la firma
    const [algorithm, hash] = signature.split('=');
    if (algorithm !== 'sha256') {
      return res.status(401).send('Algoritmo de firma no válido');
    }
    
    // Calcula la firma esperada
    const expectedSignature = crypto
      .createHmac('sha256', webhookSecret)
      .update(req.body)
      .digest('hex');
    
    // Verifica la firma usando una comparación segura contra ataques de temporización
    if (!crypto.timingSafeEqual(Buffer.from(hash, 'hex'), Buffer.from(expectedSignature, 'hex'))) {
      return res.status(401).send('Firma no válida');
    }
    
    // Analiza y procesa el webhook verificado
    const event = JSON.parse(req.body);
    console.log('Webhook de Firecrawl verificado:', event);
    
    res.status(200).send('ok');
  });

  app.listen(3000, () => console.log('Escuchando en el puerto 3000'));
  ```

  ```python Python/Flask theme={null}
  import hmac
  import hashlib
  from flask import Flask, request, abort

  app = Flask(__name__)

  WEBHOOK_SECRET = 'your-webhook-secret-here'  # Consíguelo en el panel de Firecrawl

  @app.post('/webhook/firecrawl')
  def webhook():
      signature = request.headers.get('X-Firecrawl-Signature')
      
      if not signature:
          abort(401, 'Falta el encabezado de la firma')
      
      # Extrae el hash del encabezado de la firma
      try:
          algorithm, hash_value = signature.split('=', 1)
          if algorithm != 'sha256':
              abort(401, 'Algoritmo de firma inválido')
      except ValueError:
          abort(401, 'Formato de firma inválido')
      
      # Calcula la firma esperada
      expected_signature = hmac.new(
          WEBHOOK_SECRET.encode('utf-8'),
          request.data,
          hashlib.sha256
      ).hexdigest()
      
      # Verifica la firma usando una comparación segura frente a ataques de tiempo
      if not hmac.compare_digest(hash_value, expected_signature):
          abort(401, 'Firma inválida')
      
      # Analiza y procesa el webhook verificado
      event = request.get_json(force=True)
      print('Webhook de Firecrawl verificado:', event)
      
      return 'ok', 200

  if __name__ == '__main__':
      app.run(port=3000)
  ```
</CodeGroup>

<div id="best-practices">
  ## Buenas prácticas
</div>

* **Verifica cada solicitud.** Comprueba siempre la firma antes de procesar una carga útil de webhook. Rechaza cualquier solicitud que no supere la verificación con un código de estado `401`.
* **Usa comparaciones seguras en tiempo constante.** Las comparaciones de cadenas estándar pueden filtrar información por temporización. Usa `crypto.timingSafeEqual()` en Node.js o `hmac.compare_digest()` en Python.
* **Expón tu endpoint a través de HTTPS.** Esto garantiza que las cargas útiles de webhook estén cifradas durante la transmisión.
