CentralCSP
FonctionnalitésAlertesCanaux

Webhook

Envoyez les alertes CentralCSP vers votre propre endpoint en JSON signé. Format du payload, headers de signature HMAC-SHA256 et code de vérification.

Dernière mise à jour:

Un canal webhook envoie chaque alerte en POST au format JSON vers un endpoint que vous opérez, signée avec un secret partagé pour que vous puissiez vérifier qu'elle vient bien de nous. Utilisez-le pour tout ce que les types de chat intégrés ne couvrent pas, comme l'ingestion PagerDuty ou Opsgenie, un système de tickets ou votre propre automatisation.

Prérequis

  • Le rôle Gestionnaire sur le site dans CentralCSP.
  • Un endpoint https sur un hôte public qui accepte les requêtes POST. Les adresses internes et privées sont rejetées, dont localhost, .local, .internal, les hôtes sans point, et tout ce qui pointe vers une plage d'IP privée.

1. Ajouter le canal

  1. Dans le tableau de bord, allez dans Alertes > Configuration > Ajouter un canal.
  2. Nommez le canal, choisissez le type Webhook et saisissez l'URL de votre endpoint.
  3. Saisissez un secret de signature d'au moins 8 caractères. Générez-en un aléatoire et stockez-le là où votre endpoint peut le lire.
  4. Enregistrez.

Le secret est stocké et jamais renvoyé par l'API. Modifier le canal plus tard affiche un aperçu masqué ; laissez le champ vide pour conserver la valeur actuelle.

2. Traiter la requête

Chaque envoi est un POST avec un corps JSON et deux headers :

POST /your-endpoint HTTP/1.1
content-type: application/json
x-centralcsp-timestamp: 1754640000000
x-centralcsp-signature: sha256=8b1a9953c4611296a827abf8c47804d7...

Le corps contient l'alerte, la règle, le site et les détections :

{
  "id": "0198f2c1-9a10-7c3e-8d21-5b7e0f4a6c90",
  "eventId": "0198f2c1-7d4e-7a21-b3aa-2f6f0c9d4e11",
  "deliveryId": "0198f2c1-8b2f-7e45-a1c3-9d0e4f5a6b72",
  "test": false,
  "eventType": "csp-violation:new-type",
  "rule": "New violation types",
  "title": "New CSP violation: cdn.evil.example (script-src) · blocked",
  "website": {
    "id": "0198f2c1-1111-7a21-b3aa-2f6f0c9d4e22",
    "name": "Shop",
    "url": "https://shop.example.com",
    "tags": ["Production"]
  },
  "findings": [
    {
      "kind": "csp-violation:new-type",
      "key": "script-src\nhttps://cdn.evil.example",
      "effectiveDirective": "script-src",
      "blockedUrlOrigin": "https://cdn.evil.example",
      "firstSeen": "2026-08-27T09:12:00.000Z",
      "count": 41,
      "firstPage": "https://shop.example.com/checkout",
      "exampleBlockedUrl": "https://cdn.evil.example/loader.js",
      "disposition": "enforce",
      "blockedCount": 41,
      "reportedCount": 0,
      "url": "https://app.centralcsp.com/..."
    }
  ],
  "findingsCount": 1,
  "window": {
    "start": "2026-08-27T09:00:00.000Z",
    "end": "2026-08-27T09:15:00.000Z"
  },
  "dashboardUrl": "https://app.centralcsp.com/...",
  "manageUrl": "https://app.centralcsp.com/..."
}
ChampSignification
idUnique à cette requête
eventIdL'alerte. Identique sur chaque canal et chaque nouvelle tentative, utilisez-le pour dédupliquer. null pour un test
deliveryIdCet envoi vers ce canal. null pour un test
testtrue pour un test envoyé depuis le canal
titleLe titre que chaque canal affiche
website.tagsLes tags du site
findingsJusqu'à 10 détections, chacune avec une url vers sa preuve dans le dashboard
findingsCountToutes les détections de l'alerte, y compris celles au-delà des 10 listées
manageUrlL'historique des envois de la règle dans le dashboard

La forme du tableau findings dépend de eventType ; chaque détection porte un kind correspondant à l'événement. Les détections de politique ajoutent disposition (enforce quand le navigateur a bloqué, report quand il a seulement signalé, both) avec blockedCount et reportedCount. Les détections de technologies ajoutent leurs avis (cves, chacun avec id, severity, summary, fixedIn et url), upgradeTo et upgradeReason, qui vaut replace avec un upgradeTo à null quand aucune version maintenue n'existe. La référence de l'API documente chaque type de détection. Répondez avec n'importe quel statut 2xx. Tout le reste compte comme un échec : les redirections ne sont pas suivies, et après cinq échecs consécutifs le canal se désactive tout seul.

3. Vérifier la signature

La signature est un HMAC-SHA256 sur `${timestamp}.${body}` calculé avec votre secret, encodé en hexadécimal, préfixé par sha256=. Vérifiez-la, et rejetez les timestamps trop anciens pour bloquer les rejeux :

verify.js
import { createHmac, timingSafeEqual } from "node:crypto";

function verify(secret, headers, rawBody) {
  const timestamp = headers["x-centralcsp-timestamp"];
  const received = headers["x-centralcsp-signature"];
  if (!timestamp || !received) return false;

  // Reject anything older than 5 minutes.
  if (Math.abs(Date.now() - Number(timestamp)) > 5 * 60 * 1000) return false;

  const expected =
    "sha256=" +
    createHmac("sha256", secret)
      .update(`${timestamp}.${rawBody}`)
      .digest("hex");
  return (
    expected.length === received.length &&
    timingSafeEqual(Buffer.from(expected), Buffer.from(received))
  );
}

Calculez le HMAC sur le corps brut de la requête, avant tout parsing JSON ; un corps re-sérialisé ne correspondra pas.

4. Tester le canal

Sélectionnez Tester sur le nouveau canal. CentralCSP envoie aussitôt une alerte d'exemple, construite à partir d'une fausse violation CSP, avec test à true, et signée comme un envoi réel : vous pouvez donc mettre au point votre vérification avec elle.

Étapes suivantes

On this page