# Webhook-Signaturverifizierung: HMAC-SHA256 und Replay-Schutz

> Ein webhook wird durch eine HMAC-SHA256-Signatur authentifiziert, die der Absender über einen Timestamp plus den exakten rohen Body mit einem gemeinsamen Secret berechnet und in einem Header sendet. Der Empfänger berechnet das HMAC neu, vergleicht es in konstanter Zeit und weist die Anfrage ab, wenn die Signatur nicht stimmt oder der Timestamp außerhalb eines Toleranzfensters liegt (Replay-Schutz).

- Kanonische URL: https://www.broadnet.me/de/reference/webhook-signature-verification
- Sprache: de
- Zuletzt aktualisiert: 2026-07-19
- Herausgeber: BroadNet (https://www.broadnet.me)

Wie man verifiziert, dass ein webhook authentisch und unverändert ist: HMAC-SHA256 über den rohen Body, die Signatur- und Timestamp-Header, Replay-Schutz per Timestamp-Toleranz und Nonce, konstantzeitiger Vergleich gegen Timing-Angriffe und sichere Secret-Rotation.

## Warum Signaturen statt IP-Allowlists

Ein Webhook-Endpoint ist eine öffentliche HTTPS-URL, also kann jeder ein POST darauf absetzen. TLS beweist, dass der Client Ihren Server erreicht hat; es beweist nicht, dass die Anfrage tatsächlich von der Messaging-Plattform kam. IP-Allowlisting ist brüchig (Absender-IPs ändern sich, und hinter gemeinsamem Egress versagt es). Die Standardantwort ist ein Keyed Message Authentication Code: Absender und Empfänger teilen ein Secret, der Absender signiert jedes Payload damit, und der Empfänger verifiziert. HMAC (RFC 2104) mit SHA-256 (RFC 6234) ist die allgegenwärtige Konstruktion, weil sie schnell, standardisiert und — anders als ein bloßer Hash aus Secret verkettet mit Nachricht — nachweislich resistent gegen Length-Extension-Angriffe ist. Eine gültige Signatur beweist zweierlei zugleich: das Payload wurde von einem Inhaber des Secrets erzeugt und es wurde auf dem Transportweg nicht verändert.

## Die Signatur- und Timestamp-Header

Der Absender fügt mindestens zwei Header hinzu: einen Timestamp (wann die Anfrage signiert wurde) und eine Signatur. Der signierte Inhalt ist nicht das JSON allein, sondern ein kanonischer String, der den Timestamp an den Body bindet — typischerweise der Timestamp, ein Trennzeichen und der rohe Request-Body — sodass ein Angreifer eine gültige Signatur nicht auf ein anderes Payload heben oder zu einer anderen Zeit erneut abspielen kann. Die Benennung variiert je nach Anbieter (Webhook-Signature / Webhook-Timestamp oder X-Signature / X-Timestamp), die Konstruktion ist jedoch dieselbe. Die Signatur ist meist hex oder base64 und trägt oft ein Schema-Präfix (zum Beispiel v1,), sodass das Secret auf ein neues Schema rotiert werden kann, ohne alte Verifizierer zu brechen.

*Signierter Inhalt und Header-Layout*

```text
signed_content = timestamp + '.' + raw_body
signature      = HMAC_SHA256(secret, signed_content)

Webhook-Timestamp: 1752916522
Webhook-Signature: v1,3f2b8c9a1d...   # hex or base64, scheme-prefixed
```

## Verifizierung gegen den rohen Body

Der mit Abstand häufigste Verifizierungsfehler ist, einen neu serialisierten Body zu signieren. HMAC wird über exakte Bytes berechnet, daher muss der Empfänger gegen den rohen Request-Body genau so verifizieren, wie er empfangen wurde — vor jedem JSON-Parse-und-Neucodieren. Das Parsen zu einem Objekt und erneute Stringifizieren ordnet Schlüssel um, ändert Whitespace und normalisiert Zahlen und Unicode-Escapes, was andere Bytes und eine Signaturabweichung erzeugt, selbst wenn nichts manipuliert wurde. Praktisch bedeutet das, den rohen Body im Web-Framework zu erfassen, bevor die Body-Parsing-Middleware ihn konsumiert, das HMAC über diese Bytes zu verifizieren und erst dann das JSON zur Nutzung zu parsen. Auch der Zeichensatz zählt: signieren und verifizieren Sie dieselbe Oktett-Sequenz (UTF-8), nicht einen dekodierten String.

*Verifizieren (Pseudocode) — roher Body, konstante Zeit*

```text
raw   = request.raw_body            # exact bytes, pre-parse
ts    = header('Webhook-Timestamp')
sig   = header('Webhook-Signature')

if abs(now() - ts) > TOLERANCE: reject   # replay window
expected = hmac_sha256(secret, ts + '.' + raw)
if not constant_time_equal(expected, sig): reject
accept(parse_json(raw))
```

## Replay-Schutz: Timestamp-Toleranz und Nonce

Eine Signatur allein stoppt Replay nicht — eine abgefangene, aber gültige Anfrage könnte später erneut gesendet werden. Zwei Mechanismen schließen diese Lücke. Erstens: da der Timestamp Teil des signierten Inhalts ist, prüft der Empfänger ihn gegen seine eigene Uhr und weist alles ab, das älter als eine Toleranz ist (üblicherweise wenige Minuten, breit genug, um Uhr-Drift und Retry-Verzögerung abzufangen, eng genug, um das Replay-Fenster zu begrenzen). Zweitens: für strengere Garantien merkt sich der Empfänger eine Nonce — die eindeutige Event-ID — für die Dauer der Toleranz und weist eine zweite Anfrage mit einer bereits gesehenen ID ab. Die Timestamp-Toleranz begrenzt das Fenster; der Nonce-Cache macht Replay innerhalb dieses Fensters wirkungslos. Beachten Sie, dass dies komplementär zur Consumer-Idempotenz ist, die legitime Duplikate behandelt statt böswilliger Replays.

*Kontrollen zum Replay-Schutz*

| Kontrolle | Verteidigt gegen | Tuning |
|---|---|---|
| Zeitstempel im signierten Inhalt | Übertragen einer Signatur auf einen neuen Zeitpunkt | Muss signiert sein, kein bloßer Header |
| Toleranzfenster für den Zeitstempel | Verzögerte Wiedergabe einer abgefangenen Anfrage | Wenige Minuten; Abwägung zwischen Uhrenabweichung und Angriffsfenster |
| Nonce-/Event-ID-Cache | Wiedergabe innerhalb des Toleranzfensters | IDs mindestens für die Dauer der Toleranz cachen |
| Vergleich in konstanter Zeit | Timing-Seitenkanal auf der Signatur | Immer, ungeachtet des oben Genannten |

## Konstantzeitiger Vergleich

Die berechnete und die empfangene Signatur mit einem gewöhnlichen Gleichheitsvergleich zu vergleichen, gibt Information preis: ein Byte-für-Byte-Vergleich kehrt bei einer frühen Abweichung schneller zurück, und ein Angreifer, der dieses Timing messen kann, kann die korrekte Signatur Byte für Byte rekonstruieren. Die Verifizierung muss daher einen konstantzeitigen (längenunabhängigen) Vergleich verwenden — den Timing-Safe-Vergleich der Standardbibliothek der jeweiligen Plattform —, der stets die volle Länge prüft, bevor er zurückkehrt. Das ist günstig und nicht verhandelbar; es ist der Unterschied zwischen einem soliden Signaturschema und einem, das sich mit genügend zeitgemessenen Anfragen aushebeln lässt.

## Secret-Rotation

Signier-Secrets müssen rotierbar sein, ohne legitime webhooks mitten im Flug zu verlieren. Das sichere Muster sind überlappende Keys: der Absender erhält ein neues Secret, während das alte gültig bleibt, und während der Überlappung signiert der Absender entweder mit beiden (und gibt zwei Signaturen aus) oder der Empfänger akzeptiert eine Signatur, die zu einem der beiden Secrets passt. Sobald jeder Producer auf dem neuen Secret bestätigt ist, wird das alte ausgemustert. Das Schema-Präfix auf der Signatur (v1, v2,) macht dies beobachtbar und lässt einen versionierten Algorithmuswechsel mitfahren. BroadNets gehosteter Webhook-Signaturvalidator lässt Sie ein Payload, einen Timestamp und ein Secret ohne Code gegen ein erwartetes HMAC prüfen; die Mechanik der HMAC-SHA256-DLR-Signierung wird in der Answers-Bibliothek behandelt.

## Häufige Fragen

### Wie wird eine Webhook-Signatur berechnet?

Der Absender baut einen kanonischen String, der den Timestamp an den rohen Body bindet (typischerweise Timestamp + '.' + Body), berechnet darüber HMAC-SHA256 mit einem gemeinsamen Secret und legt das Ergebnis zusammen mit dem Timestamp in einen Signatur-Header. Der Empfänger berechnet dasselbe HMAC neu und vergleicht. Eine Übereinstimmung beweist, dass das Payload von einem Secret-Inhaber stammt und nicht verändert wurde.

### Warum muss ich gegen den rohen Request-Body verifizieren?

HMAC wird über exakte Bytes berechnet. Wenn Sie das JSON parsen und neu serialisieren, ändern sich Schlüsselreihenfolge, Whitespace, Zahlenformat und Unicode-Escapes, sodass die Bytes abweichen und die Signatur nicht passt, selbst wenn nichts manipuliert wurde. Erfassen Sie den rohen Body vor der Body-Parsing-Middleware, verifizieren Sie, und parsen Sie erst dann.

### Wie stoppt die Timestamp-Toleranz Replay-Angriffe?

Der Timestamp ist Teil des signierten Inhalts, kann also nicht verändert werden, ohne die Signatur zu brechen. Der Empfänger vergleicht ihn mit seiner eigenen Uhr und weist alles ab, das älter als eine Toleranz ist (üblicherweise wenige Minuten). Das begrenzt, wie lange eine abgefangene gültige Anfrage abgespielt werden kann; ein Nonce-Cache schließt Replays innerhalb dieses Fensters.

### Warum ist ein konstantzeitiger Vergleich erforderlich?

Ein gewöhnlicher Gleichheitsvergleich kehrt beim ersten abweichenden Byte früh zurück, und ein Angreifer, der die Antwort zeitlich messen kann, kann die korrekte Signatur Byte für Byte rekonstruieren. Ein konstantzeitiger Vergleich prüft stets die volle Länge, bevor er zurückkehrt, und entfernt so den Timing-Seitenkanal. Verwenden Sie die Timing-Safe-Vergleichsfunktion der Plattform.

### Wie rotiere ich ein Webhook-Signier-Secret sicher?

Mit überlappenden Keys. Stellen Sie das neue Secret bereit, während das alte gültig bleibt; während der Überlappung signiert der Absender mit beiden oder der Empfänger akzeptiert eines von beiden, sodass kein legitimer webhook verloren geht. Sobald alle Producer auf dem neuen Secret bestätigt sind, mustern Sie das alte aus. Ein Schema-Präfix auf der Signatur macht den Übergang beobachtbar.

### Reicht HTTPS nicht aus, um einem webhook zu vertrauen?

Nein. TLS beweist, dass der Transport verschlüsselt war und der Client Ihren Server erreicht hat, aber nicht, dass die Anfrage von der Messaging-Plattform kam — jeder kann ein POST auf eine öffentliche URL absetzen. Nur eine HMAC-Signatur mit gemeinsamem Secret authentifiziert den Absender und beweist, dass das Payload nicht verändert wurde. IP-Allowlisting ist ein schwacher Ersatz, weil Egress-IPs sich ändern.

## Quellen

- [IETF RFC 2104 — HMAC: Keyed-Hashing for Message Authentication](https://datatracker.ietf.org/doc/html/rfc2104)
- [IETF RFC 6234 — US Secure Hash Algorithms (SHA and HMAC-SHA)](https://datatracker.ietf.org/doc/html/rfc6234)

## Verwandte Seiten

- [Webhook-Zustellung & Zuverlässigkeit](https://www.broadnet.me/de/reference/webhook-delivery-and-reliability)
- [Nachrichtenstatus- & Inbound-Webhooks](https://www.broadnet.me/de/reference/message-status-and-inbound-webhooks)
- [API-Authentifizierung & Signierung](https://www.broadnet.me/de/reference/api-authentication-and-signing)
- [Webhook-Signaturvalidator](https://www.broadnet.me/de/tools/webhook-signature-validator)
- [HMAC-SHA256-DLR-Signierung](https://www.broadnet.me/de/answers/hmac-sha256-dlr-signing)
