Zum Inhalt springen

Die Signatur einer Zustellung prüfen

HMAC-SHA256 über den rohen Rumpf nachrechnen, in konstanter Zeit mit X-Signature vergleichen, nach X-Delivery-Id entdoppeln und das Secret rotieren.

3 Minuten LesezeitWebhooksStand: 25.10.2026

Auf dieser Seite

Bevor Sie loslegen

Für wen
Wer den Empfänger für Webhooks programmiert.
Voraussetzung
Ein angelegter Endpunkt und sein Signatur-Secret (whsec_…), wie es beim Anlegen oder nach Secret rotieren angezeigt wurde.
Ort
Ihr eigener Code; das Secret erneuern Sie unter Einstellungen › Organisation › Webhooks.

Am Ende nimmt Ihr Empfänger nur Zustellungen an, die wirklich von der Plattform stammen, verarbeitet jede genau einmal und übersteht einen Wechsel des Secrets.

Schritte

  1. Lesen Sie den Rumpf als rohe Bytes, bevor irgendetwas ihn als JSON deutet. Die Signatur gilt für genau die Bytes, die gesendet wurden; wer den Rumpf erst einliest und neu serialisiert, ändert womöglich Reihenfolge oder Abstände und bekommt eine andere Signatur.
  2. Rechnen Sie HMAC-SHA256 über diese Bytes mit dem Secret als Schlüssel und kodieren Sie das Ergebnis base64url, so wie Node.js es mit digest('base64url') erzeugt.
  3. Vergleichen Sie mit X-Signature in konstanter Zeit und nur bei gleicher Länge. Ein gewöhnlicher Zeichenvergleich bricht beim ersten Unterschied ab und verrät über die Laufzeit, wie viele Zeichen stimmen.
  4. Verzweigen Sie nach X-Event-Type. Die Kopfzeile nennt den Ereignistyp, ohne dass Sie den Rumpf lesen müssen.
  5. Entdoppeln Sie nach X-Delivery-Id. Merken Sie sich jede verarbeitete Nummer. Eine Wiederholung trägt dieselbe Nummer; ist sie bekannt, antworten Sie mit 2xx und tun sonst nichts.
  6. Erst jetzt verarbeiten — und schnell mit 2xx antworten. Das Zeitlimit beträgt zehn Sekunden; lange Arbeit gehört hinter die Antwort.

So sieht die Prüfung in Node.js aus; es ist das Beispiel, das auch das Portal unter Zustellungen auf Echtheit prüfen zeigt:

import { createHmac, timingSafeEqual } from 'node:crypto';

// Über den ROHEN Rumpf signieren, nicht über neu serialisiertes JSON:
// jede erneute Serialisierung kann Reihenfolge oder Abstände ändern.
export function isFromSignage(rawBody: string, header: string, secret: string): boolean {
  const expected = createHmac('sha256', secret).update(rawBody).digest('base64url');
  const a = Buffer.from(expected);
  const b = Buffer.from(header);
  return a.length === b.length && timingSafeEqual(a, b);
}

Der Aufruf im Empfänger: isFromSignage(rawBody, req.headers['x-signature'], process.env.WEBHOOK_SECRET). Kopfzeilennamen kommen je nach Server in Kleinbuchstaben an; die Plattform sendet X-Signature.

Optionen

Das Secret erneuern

Das Secret hat die Form whsec_ plus mindestens 32 Zeichen aus A–Z, a–z, 0–9, _ und -. Es wird nur beim Anlegen und nach einer Rotation angezeigt; abrufen lässt es sich nicht. Ist es verloren oder soll es gewechselt werden:

  1. Stellen Sie Ihren Empfänger so ein, dass er das neue Secret sofort nach der Anzeige übernehmen kann — etwa über eine Konfiguration, die ohne Neustart nachlädt.
  2. Klicken Sie im Portal an dem Endpunkt auf Secret rotieren (ohne ein Paket mit Webhooks gesperrt), oder rufen Sie POST /v1/webhooks/{id}/rotate-secret auf — über die API bleibt das auch ohne Paket möglich.
  3. Übernehmen Sie das neue Secret aus dem Kasten Signatur-Secret — nur jetzt sichtbar (Secret kopieren) beziehungsweise aus der Antwort {"secret": "whsec_…"}.

Ab dem nächsten Versand wird ausschließlich mit dem neuen Secret signiert — auch Wiederholungen älterer Zustellungen. Es gibt keine Übergangsphase, in der beide gelten. Bis Ihr Empfänger das neue Secret kennt, weist er echte Zustellungen ab; die Plattform wiederholt sie nur, wenn Sie in dieser Zeit mit 5xx statt 4xx antworten. Adresse, Ereignisse und Zustell-Historie des Endpunkts bleiben bei der Rotation erhalten.

Ergebnis prüfen

  • Eine echte Zustellung passiert die Prüfung, und im Zustell-Log steht sie als Zugestellt mit Ihrem Antwortcode.
  • Eine Anfrage mit verändertem Rumpf oder ohne gültige X-Signature wird abgewiesen.
  • Eine erneut zugestellte Nummer (Erneut zustellen im Zustell-Log) löst bei Ihnen keine zweite Verarbeitung aus.

Wenn etwas nicht klappt

Symptom Bedeutung Lösung
Signatur passt nie Der Rumpf wurde vor der Prüfung verändert (neu serialisiert, Zeichensatz umgewandelt, Leerraum entfernt) Rohe Bytes prüfen, bevor ein JSON-Parser oder ein Rahmenwerk den Rumpf anfasst
Signatur passt seit einem bestimmten Zeitpunkt nicht mehr Das Secret wurde rotiert; Ihr Empfänger prüft noch mit dem alten Neues Secret übernehmen; Zustellungen aus der Lücke im Zustell-Log Erneut zustellen
Signatur passt, Vergleich schlägt trotzdem fehl Längenprüfung oder Kodierung stimmen nicht (hex statt base64url, Füllzeichen angehängt) Genau die Form aus dem Beispiel verwenden
Dieselbe Zustellung wird zweimal verarbeitet Entdopplung fehlt; eine Wiederholung oder ein manuelles Erneut-Zustellen trug dieselbe X-Delivery-Id Nummern speichern und bekannte Nummern mit 2xx quittieren

Weiterführendes