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
- 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.
- 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. - Vergleichen Sie mit
X-Signaturein 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. - Verzweigen Sie nach
X-Event-Type. Die Kopfzeile nennt den Ereignistyp, ohne dass Sie den Rumpf lesen müssen. - 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. - 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:
- 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.
- Klicken Sie im Portal an dem Endpunkt auf Secret rotieren (ohne ein Paket mit Webhooks gesperrt), oder rufen Sie
POST /v1/webhooks/{id}/rotate-secretauf — über die API bleibt das auch ohne Paket möglich. - Ü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-Signaturewird 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 |