Webhook-Signatur-Validator
Ihr Anbieter sendet einen Signatur-Header, Ihr Handler sagt, er stimme nicht überein, und die Doku antwortet mit einem SDK zum Installieren. Das sagt Ihnen nicht warum. Fügen Sie unten Signatur, Secret und Rohbody ein: Wir berechnen den HMAC im Browser neu und probieren bei Fehlschlag die üblichen Ursachen durch — ein Leerzeichen im Secret, ein abschließender Zeilenumbruch, ein neu serialisierter Body, ein veralteter Timestamp.
Kurz gesagt: Eine Webhook-Signatur scheitert fast immer an einem von fünf Gründen — falsches Secret (Test vs. Live), ein vom Framework neu serialisierter Body, ein Timestamp außerhalb des 5-Minuten-Fensters, ein abschließender Zeilenumbruch oder ein übrig gebliebenes Präfix sha256= / v0=. Dieses Tool berechnet den HMAC neu und sagt Ihnen, welcher.
Fügen Sie eine fehlschlagende Signatur ein
Die vier Signaturschemata
Alle vier sind HMAC, unterscheiden sich aber darin, was gehasht und wie das Ergebnis kodiert wird. Ein falsches Detail und jede Zustellung schlägt fehl.
| Anbieter | Was signiert wird | Algorithmus |
|---|---|---|
| Stripe | HMAC von t.body; Signatur und Timestamp in einem Stripe-Signature-Header | SHA-256 hex |
| GitHub | HMAC des Rohbodys; Signatur in X-Hub-Signature-256 | SHA-256 hex |
| Shopify | HMAC des Rohbodys; Signatur in X-Shopify-Hmac-Sha256 | SHA-256 base64 |
| Slack | HMAC von v0:timestamp:body; braucht auch den Timestamp-Header | SHA-256 hex |
Twilio ist die Ausnahme — es hasht eine kanonische URL plus sortierte Parameter, nicht den Body. Nutzen Sie dafür den Twilio-Signatur-Validator.
Die fünf echten Ursachen
Sortiert danach, wie oft sie in Support-Threads auftauchen.
| # | Ursache | Symptom | Lösung |
|---|---|---|---|
| 1 | Falsches Secret | Jede Zustellung scheitert, auch eine frische | Test-vs.-Live-Verwechslung — Anbieter vergeben pro Modus und pro Endpoint ein anderes Signing-Secret. |
| 2 | Neu serialisierter Body | Scheitert, nachdem das Framework das JSON geparst hat | Signieren Sie die Rohbytes, nicht JSON.stringify(parsed): Abstände und Schlüsselreihenfolge ändern den Hash. |
| 3 | Veralteter Timestamp | Klappt im Test, scheitert bei erneut gesendeten Events | Stripe und Slack lehnen alles über 5 Minuten ab. Senden Sie kein Stunden altes Event erneut. |
| 4 | Abschließender Zeilenumbruch | Body um ein Byte daneben, Signatur nie korrekt | Ein Proxy oder Editor hat einen Zeilenumbruch angehängt. Das Tool erkennt genau diesen Fall. |
| 5 | Präfix wörtlich verglichen | sha256= oder v0= im Vergleich enthalten | Vergleichen Sie nur den hex-/base64-Teil, nicht das Schema-Präfix. |
Die Rohbody-Falle
Die häufigste Ursache: Sie prüfen gegen den geparsten-dann-neu-serialisierten Body statt gegen die exakten Bytes. JSON.stringify(JSON.parse(body)) ändert Abstände und Schlüsselreihenfolge, sodass der HMAC nicht mehr passt. Lesen Sie den Rohbody, bevor irgendetwas ihn parst.
// Express: keep the RAW bytes, do NOT let JSON re-serialise them
app.post('/webhook', express.raw({ type: '*/*' }), (req, res) => {
const raw = req.body; // Buffer, exactly as received
verify(raw, req.headers['stripe-signature'], secret);
});# Flask: request.get_data() returns the raw body; request.json does NOT raw = request.get_data() # bytes, untouched verify(raw, request.headers['X-Hub-Signature-256'], secret)
// Next.js App Router: read the text before parsing
export async function POST(req) {
const raw = await req.text(); // sign THIS, not JSON.stringify(await req.json())
verify(raw, req.headers.get('stripe-signature'), secret);
}Faustregel: Signatur und Rohbytes am Rand erfassen, prüfen, dann parsen.
Timestamps und Replays
Stripe und Slack integrieren einen Timestamp in den signierten String und lehnen alles über fünf Minuten ab — das ist Replay-Schutz, kein Bug. GitHub und Shopify tun das nicht, eine gültige GitHub-Signatur bleibt also für immer gültig. Zeigt das Tool gültig, aber abgelaufen, sind Secret und Body in Ordnung; Sie senden nur ein altes Event erneut. Erzeugen Sie eine frische Zustellung, statt eine erfasste erneut zu senden.
Sobald die Signatur stimmt
Möchten Sie ein korrekt signiertes Test-Event an Ihren Endpoint senden? Der Webhook-Signer baut eines für alle sechs Anbieter. Um echte Zustellungen zu erfassen und zu inspizieren, leiten Sie sie an einen Relay-Tunnel.
Häufige Fragen
Speichern Sie mein Signing-Secret?
Nein. Der HMAC wird im Browser mit Web Crypto berechnet; Secret und Body erreichen unsere Server nie. Öffnen Sie den Netzwerk-Tab: Beim Klick auf Prüfen geht keine Anfrage raus.
Welche Anbieter werden unterstützt?
Stripe, GitHub, Shopify und Slack — die vier HMAC-über-Body-Schemata. Twilio signiert stattdessen eine kanonische URL und hat ein eigenes Tool: den Twilio-Signatur-Validator.
Es klappt hier, mein Server lehnt trotzdem ab. Warum?
Fast immer der Body. Ihr Framework hat das JSON geparst und Sie haben es vor der Prüfung neu serialisiert, was Abstände und Schlüsselreihenfolge ändert. Signieren Sie die Rohbytes — siehe die Express-, Flask- und Next-Snippets oben.
Was bedeutet „gültig, aber abgelaufen“?
Der HMAC ist korrekt, aber Stripe und Slack lehnen Signaturen über fünf Minuten ab, um Replays zu blockieren. Wenn Sie ein Event erfasst und später erneut senden, scheitert die Prüfung am Timestamp, obwohl das Secret stimmt.