Skip to main content
Hoe webhooks werken
Language

Webhooks

Stel webhook-bestemmingen in om cside-beveiligingswaarschuwingen te ontvangen via HTTP POST-verzoeken met HMAC-handtekeningverificatie.

Hoe webhooks werken

Met webhooks kunt u cside-notificaties ontvangen als HTTP POST-verzoeken naar een URL die u opgeeft. Wanneer een trigger wordt geactiveerd, stuurt cside een JSON-payload naar uw webhook-endpoint met details over de gebeurtenis.

U kunt webhooks in drie formaten configureren:

  • JSON - standaard JSON-payload voor aangepaste integraties
  • Slack - voorgeformatteerd voor Slack-kanalen
  • Discord - voorgeformatteerd voor Discord-kanalen

Zie Jira Automation om op elk plan Jira-werkitems aan te maken vanuit webhooks.

Een webhook-bestemming toevoegen

Om een webhook als bestemming toe te voegen aan een notificatieconfiguratie:

  1. Open het dashboard en navigeer naar Team Settings > Notifications
  2. Maak een nieuwe notificatieconfiguratie aan of bewerk een bestaande
  3. Klik onder Send To op Add destination en selecteer Webhook
  4. Vul in het configuratiepaneel het volgende in:
    • URL: de URL waar u webhook-notificaties wilt ontvangen (bijv. https://example.com/cside/notify)
    • Secret: een geheime sleutel die wordt gebruikt om webhook-verzoeken te ondertekenen (gebruikt voor HMAC-verificatie)
    • Format: kies JSON, Slack of Discord
  5. Klik op Save of Save & Test

cside ondertekent elk verzoek met de x-cside-signature-header, maar kan geen aangepaste headers toevoegen. Als uw ontvanger authenticeert met een eigen header, controleer dan of deze het token ook in de URL accepteert, zoals Jira Automation doet.

De webhook-payload

cside stuurt één HTTP POST per gebeurtenis, met Content-Type: application/json en een x-cside-signature-header (zie HMAC-verificatie). Elke payload bevat een event-veld op het hoogste niveau dat het type gebeurtenis aanduidt, een tijdstempel, het team of domein waar de gebeurtenis bij hoort en een gebeurtenisspecifiek data-object.

Het veld dat de tijdstempel bevat verschilt per gebeurtenis: alert.created en de samenvattingsgebeurtenissen gebruiken timestamp, terwijl security_headers.changed sent_at gebruikt. Lees eerst event en verwerk daarna de rest van de payload volgens de tabellen hieronder. Behandel onbekende velden als optioneel, zodat nieuwe velden uw integratie niet breken.

Elke JSON-payload bevat ook twee voor mensen leesbare velden, summary (een titel van één regel) en description (details over meerdere regels), zowel op het hoogste niveau als herhaald binnen data. Gebruik ze om een ticket of chatbericht in te vullen zonder per gebeurtenis uw eigen tekst op te bouwen. Ze worden binnen data herhaald omdat Jira Automation een data-sleutel op het hoogste niveau speciaal behandelt.

Event-ID’s

IDVerstuurd doorTijdstempelvelddata-object
alert.createdDirecte triggers, en de trigger Vulnerable Script Detected met het directe schematimestampAlert-object
security_headers.changedSecurity Headers Changedsent_atWijziging van security headers
pci_report.availablePCI Report (dagelijks of wekelijks)timestampPCI-rapport
csp_block_digestScript Blocked by CSP (dagelijks of wekelijks)timestampSamenvatting van CSP-blokkeringen
csp_policy_digestCSP Policy Digest (dagelijks of wekelijks)timestampSamenvatting van CSP-beleid
vulnerable_script_digestVulnerable Script Detected (dagelijks of wekelijks)timestampSamenvatting van kwetsbaarheden
outbound_connections_pending_reviewOutbound Connections Pending Review (dagelijks of wekelijks)timestampOpenstaande uitgaande verbindingen

Alleen alert.created, security_headers.changed en pci_report.available respecteren de formaten Slack en Discord. De andere samenvattingsgebeurtenissen worden altijd als JSON verstuurd, ongeacht het formaat dat voor de bestemming is ingesteld.

Save & Test stuurt een voorbeeldpayload van alert.created met het trigger_type van de trigger van de regel, ook voor triggers die normaal een samenvatting afleveren. De summary daarvan begint met [Test]. Security Headers Changed stuurt in plaats daarvan een voorbeeldpayload van security_headers.changed. Als uw endpoint met een fout antwoordt, toont het testresultaat de HTTP-statuscode die het teruggaf.

Alle tijdstempels zijn ISO 8601-tekenreeksen in UTC. ID’s zijn decimale tekenreeksen.

alert.created

Wordt verstuurd voor elke waarschuwing die een directe trigger genereert: Script Threat Detected, High-risk Vulnerability, Managed Flagged, Malicious Tag Manager, Malicious Outbound Connection en Vulnerable Script Detected wanneer de regel is ingesteld op directe aflevering.

VeldTypeBeschrijving
event"alert.created"Het event-ID
timestampstringWanneer de webhook is verstuurd
domain_idstringID van het domein waarop de waarschuwing is geactiveerd
domainstringHostname van het domein waarop de waarschuwing is geactiveerd
trigger_typestringDe trigger die de waarschuwing heeft opgeleverd, zie de tabel hieronder
summarystringTitel van één regel, bijvoorbeeld [cside] Malicious Script: {ruleset} on {domain}. Dezelfde tekst die de Jira-integratie als summary van de issue gebruikt
descriptionstringUitleg van de waarschuwing in platte tekst
dataobjectHet alert-object
destination_idstringID van de webhook-bestemming die de gebeurtenis heeft ontvangen

Waarden van trigger_type:

trigger_typeTrigger
script_threat_detected_by_rules_engineScript Threat Detected
high_risk_vulnerability_detectedHigh-risk Vulnerability
vulnerable_script_detectedVulnerable Script Detected (direct schema)
cside_managed_list_flaggedManaged Flagged
malicious_tag_managerMalicious Tag Manager
malicious_outbound_connectionMalicious Outbound Connection

Alert-object

VeldTypeBeschrijving
summarystringGelijk aan summary op het hoogste niveau
descriptionstringGelijk aan description op het hoogste niveau
domainstringGelijk aan domain op het hoogste niveau
trigger_typestringGelijk aan trigger_type op het hoogste niveau
target_type"URL" | "HASH" | "IP" | "DOMAIN" | "HOSTNAME" | "VENDOR"Wat target bevat
targetstringHet onderwerp van de waarschuwing: een script-URL, een scripthash, of het gemarkeerde IP-adres, domein of de gemarkeerde hostname
action"alert"De actie die voor de waarschuwing is vastgelegd. Momenteel altijd "alert"; behandel het als een tekenreeks om compatibel te blijven met toekomstige acties
ruleset_idstringID van de ruleset die overeenkwam
ruleset_namestringNaam van de ruleset die overeenkwam
ruleset_descriptionstringBeschrijving van de ruleset die overeenkwam
script_urlsstring[]De script-URL’s die de waarschuwing hebben geactiveerd; kan leeg zijn
vuln_cve_idstring | nullKwetsbaarheids-ID (CVE of GHSA); null bij waarschuwingen die geen kwetsbaarheid betreffen
vuln_packagestring | nullGetroffen package; null bij waarschuwingen die geen kwetsbaarheid betreffen
vuln_severitystring | nullGerapporteerde ernst, zoals HIGH; null bij waarschuwingen die geen kwetsbaarheid betreffen
vuln_reference_urlstring | nullLink naar de kwetsbaarheid op osv.dev; null als er geen vuln_cve_id is

De vier vuln_*-velden worden alleen gevuld voor vulnerable_script_detected en high_risk_vulnerability_detected. Voor elk ander trigger_type zijn ze null.

{
  "event": "alert.created",
  "timestamp": "2026-09-17T10:15:30.123456Z",
  "domain_id": "1897425263682514945",
  "domain": "checkout.example.com",
  "trigger_type": "high_risk_vulnerability_detected",
  "summary": "[cside] High-risk Vulnerability: CVE-2024-1234 on checkout.example.com",
  "description": "cside detected a high-risk vulnerability on checkout.example.com: lodash. Severity: High.\n\nThis is a high-risk finding (malware or a high-severity vulnerability). Investigate it promptly: if it is malware, remove the script immediately and rotate any credentials it may have accessed; otherwise prioritize updating or removing the affected dependency.",
  "data": {
    "summary": "[cside] High-risk Vulnerability: CVE-2024-1234 on checkout.example.com",
    "description": "cside detected a high-risk vulnerability on checkout.example.com: lodash. Severity: High.\n\nThis is a high-risk finding (malware or a high-severity vulnerability). Investigate it promptly: if it is malware, remove the script immediately and rotate any credentials it may have accessed; otherwise prioritize updating or removing the affected dependency.",
    "domain": "checkout.example.com",
    "trigger_type": "high_risk_vulnerability_detected",
    "target_type": "URL",
    "target": "https://cdn.example.com/lodash.js",
    "action": "alert",
    "ruleset_id": "ruleset_vulnerability_detected",
    "ruleset_name": "Vulnerability Detected",
    "ruleset_description": "A script with a known vulnerability was loaded",
    "script_urls": ["https://cdn.example.com/lodash.js"],
    "vuln_cve_id": "CVE-2024-1234",
    "vuln_package": "lodash",
    "vuln_severity": "HIGH",
    "vuln_reference_url": "https://osv.dev/vulnerability/CVE-2024-1234"
  },
  "destination_id": "1897425263682514950"
}

security_headers.changed

Wordt verstuurd door Security Headers Changed wanneer de security headers die op de checkout-pagina’s van een domein worden waargenomen verschillen tussen twee opeenvolgende observatievensters.

VeldTypeBeschrijving
event"security_headers.changed"Het event-ID
sent_atstringWanneer de webhook is verstuurd
team_idstringID van het team dat eigenaar is van het domein
summarystring[cside] Security headers changed on {domain}
descriptionstringEén regel per gewijzigde header: - {header}: {from} -> {to}
data.summarystringGelijk aan summary
data.descriptionstringGelijk aan description
data.domain_idstringID van het domein
data.domainstringHostname van het domein
data.checkout_pathsstring[]De checkout-pagina-selectors die zijn waargenomen
data.changesobject[]Eén item per gewijzigde header
data.changes[].header_namestringDe header, bijvoorbeeld content-security-policy
data.changes[].from_valuestringDe vorige waarde; leeg als de header is toegevoegd
data.changes[].to_valuestringDe nieuwe waarde; leeg als de header is verdwenen
data.changes[].from_datestringBegin van het observatievenster waarin de vorige waarde is gezien
data.changes[].to_datestringBegin van het observatievenster waarin de nieuwe waarde is gezien

pci_report.available

Wordt verstuurd door PCI Report zodra het rapport voor de periode klaar is, voor de domeinen binnen bereik waarvoor checkout-paden zijn ingesteld. Het wordt één keer per rapport verstuurd; een geweigerde aflevering wordt niet opnieuw geprobeerd. Elk verzoek bevat ook een x-cside-delivery-id-header die gelijk blijft als hetzelfde rapport opnieuw wordt afgeleverd, zodat u daarop kunt dedupliceren.

VeldTypeBeschrijving
event"pci_report.available"Het event-ID
timestampstringWanneer de webhook is verstuurd
organization_idstringID van de organisatie
team_idstringID van het team
summarystring[cside / PCI DSS]: New PCI Compliance Report for {domains} (de eerste drie domeinen, gevolgd door “and N more”)
descriptionstringEen zin met de domeinen en datums, gevolgd door de link naar het rapport
data.summarystringGelijk aan summary
data.descriptionstringGelijk aan description
data.report_idstringID van het rapport
data.report_urlstringLink om het rapport te downloaden vanuit het cside-dashboard
data.domain_idsstring[]ID’s van de domeinen die het rapport beslaat
data.domainsstring[]Hostnames van de domeinen die het rapport beslaat, in dezelfde volgorde
data.starting_datestringBegin van de rapportageperiode
data.ending_datestringEinde van de rapportageperiode
data.period"daily" | "weekly" | "custom"De lengte van de rapportageperiode. custom wordt gebruikt voor een rapport dat een ander bereik beslaat

csp_block_digest

Wordt verstuurd door Script Blocked by CSP met de Content Security Policy-overtredingsrapporten die in de periode zijn verzameld. Er wordt niets verstuurd als er geen overtredingen waren.

VeldTypeBeschrijving
event"csp_block_digest"Het event-ID
timestampstringWanneer de webhook is verstuurd
organization_idstringID van de organisatie
team_idstringID van het team
summarystringTitel van één regel voor de samenvatting
descriptionstringUitsplitsing van de samenvatting over meerdere regels
data.summarystringGelijk aan summary
data.descriptionstringGelijk aan description
data.period"daily" | "weekly"Het schema van de regel
data.start_datestringBegin van de samenvattingsperiode
data.end_datestringEinde van de samenvattingsperiode
data.domainsobject[]Aantallen per domein, gesorteerd op aantal overtredingen
data.domains[].domain_idstringID van het domein
data.domains[].domainstringHostname van het domein
data.domains[].violation_countnumberOvertredingen die voor het domein zijn vastgelegd
data.top_blocked_urisstring[]De meest geblokkeerde URI’s
data.top_violated_directivesstring[]De meest overtreden directives
data.total_violationsnumberTotaal aantal overtredingen over alle domeinen binnen bereik

csp_policy_digest

Wordt verstuurd door CSP Policy Digest voor elk domein binnen bereik waarvan het aanbevolen Content Security Policy in de periode is gewijzigd. Er wordt niets verstuurd als er geen domein is gewijzigd.

VeldTypeBeschrijving
event"csp_policy_digest"Het event-ID
timestampstringWanneer de webhook is verstuurd
organization_idstringID van de organisatie
team_idstringID van het team
summarystringTitel van één regel voor de samenvatting
descriptionstringUitsplitsing van de samenvatting over meerdere regels
data.summarystringGelijk aan summary
data.descriptionstringGelijk aan description
data.period"daily" | "weekly"Het schema van de regel
data.domainsobject[]Eén item per domein waarvan het beleid is gewijzigd
data.domains[].domainstringHostname van het domein
data.domains[].domain_idstringID van het domein
data.domains[].addedstring[]Hosts die aan het aanbevolen beleid zijn toegevoegd
data.domains[].removedstring[]Hosts die uit het aanbevolen beleid zijn verwijderd
data.domains[].flaggedstring[]Verwijderde hosts die op de door cside beheerde dreigingslijst staan
data.domains[].host_countnumberAantal hosts in het aanbevolen beleid
data.domains[].policy_headerstringDe volledige aanbevolen waarde van de Content-Security-Policy-header

vulnerable_script_digest

Wordt verstuurd door Vulnerable Script Detected met een dagelijks of wekelijks schema, met de routinematige (niet high-risk) kwetsbaarheidsbevindingen uit de periode. Er wordt niets verstuurd als er geen bevindingen waren.

VeldTypeBeschrijving
event"vulnerable_script_digest"Het event-ID
timestampstringWanneer de webhook is verstuurd
organization_idstringID van de organisatie
team_idstringID van het team
summarystringTitel van één regel voor de samenvatting
descriptionstringUitsplitsing van de samenvatting over meerdere regels
data.summarystringGelijk aan summary
data.descriptionstringGelijk aan description
data.period"daily" | "weekly"Het schema van de regel
data.start_datestringBegin van de samenvattingsperiode
data.end_datestringEinde van de samenvattingsperiode
data.domainsobject[]Aantallen per domein
data.domains[].domain_idstringID van het domein
data.domains[].domainstringHostname van het domein
data.domains[].vulnerability_countnumberBevindingen die voor het domein zijn vastgelegd
data.top_vulnerabilitiesobject[]De meest voorkomende bevindingen
data.top_vulnerabilities[].vulnerability_idstringKwetsbaarheids-ID (CVE of GHSA)
data.top_vulnerabilities[].packagestringGetroffen package
data.top_vulnerabilities[].severitystringGerapporteerde ernst
data.top_vulnerabilities[].occurrence_countnumberHoe vaak de bevinding is voorgekomen
data.total_vulnerabilitiesnumberTotaal aantal bevindingen over alle domeinen binnen bereik

outbound_connections_pending_review

Wordt verstuurd door Outbound Connections Pending Review met het aantal uitgaande hostnames dat uw team nog niet heeft goedgekeurd in Resources inventory. Er wordt niets verstuurd als er niets openstaat.

VeldTypeBeschrijving
event"outbound_connections_pending_review"Het event-ID
timestampstringWanneer de webhook is verstuurd
organization_idstringID van de organisatie
team_idstringID van het team
summarystringTitel van één regel voor de samenvatting
descriptionstringUitsplitsing van de samenvatting over meerdere regels
data.summarystringGelijk aan summary
data.descriptionstringGelijk aan description
data.period"daily" | "weekly"Het schema van de regel
data.pending_hostname_countnumberUnieke uitgaande hostnames die op beoordeling wachten
data.domain_countnumberAantal domeinen binnen bereik waarop ze zijn waargenomen

HMAC-verificatie

Elk webhook-verzoek bevat een x-cside-signature-header met een HMAC SHA256-hash van de verzoekbody, ondertekend met het secret dat u heeft opgegeven bij het aanmaken van de webhook-bestemming.

U dient deze handtekening altijd te verifiëren om te bevestigen dat het verzoek van cside afkomstig is en replay-aanvallen te voorkomen.

Hoe de handtekening te verifiëren

Als u JavaScript gebruikt, gebruik dan ons JavaScript-pakket voor ingebouwde verificatie.

Voor andere talen berekent u de HMAC SHA256-hash van de ruwe verzoekbody met uw webhook-secret en vergelijkt u deze met de waarde van de x-cside-signature-header.

async function verifyHmac(body: string, signature: string, secret: string) {
	const encoder = new TextEncoder();
	const encodedBody = encoder.encode(body);

	const key = await crypto.subtle.importKey(
		"raw",
		encoder.encode(secret),
		{ name: "HMAC", hash: "SHA-256" },
		false,
		["sign"]
	);

	const signatureBuffer = await crypto.subtle.sign("HMAC", key, encodedBody);

	const finalSig = Array.from(new Uint8Array(signatureBuffer))
		.map((byte) => byte.toString(16).padStart(2, "0"))
		.join("");

	return signature.toLowerCase() === finalSig;
}
fn verify_hmac(body: &str, signature: &str, secret: &str) -> Result<(), &'static str> {
      let mut mac = HmacSha256::new_from_slice(secret.as_bytes()).map_err(|_| "Invalid secret")?;
      mac.update(body.as_bytes());
      let result = mac.finalize();
      let code_bytes = result.into_bytes();
      let final_sig = hex::encode(code_bytes);

      if signature.to_lowercase() == final_sig {
          Ok(())
      } else {
          Err("Invalid signature")
      }
  }

  // Add to Cargo.toml:
  // [dependencies]
  // hmac = "0.12"
  // sha2 = "0.10"
  // hex = "0.4"
package main

import (
  "crypto/hmac"
  "crypto/sha256"
  "encoding/hex"
  "strings"
)

func verifyHmac(body, signature, secret string) bool {
	h := hmac.New(sha256.New, []byte(secret))
	h.Write([]byte(body))
	finalSig := hex.EncodeToString(h.Sum(nil))

	return strings.ToLower(signature) == finalSig
}
defmodule HmacVerifier do
	def verify_hmac(body, signature, secret) do
		final_sig =
			:crypto.mac(:hmac, :sha256, secret, body)
			|> Base.encode16(case: :lower)

			String.downcase(signature) == final_sig
	end
end
import hmac
import hashlib
import secrets

def verify_hmac(body: str, signature: str, secret: str) -> bool:
	final_sig = hmac.new(
		secret.encode('utf-8'),
		body.encode('utf-8'),
		hashlib.sha256
	).hexdigest()

	return signature.lower() == final_sig
Was this page helpful?