Ein Webhook ist ein HTTP-Request, den ein fremdes System an eine eigene URL sendet, sobald etwas passiert (z. B. „Zahlung eingegangen“). Das ist bequem – und gleichzeitig ein Einfallstor, wenn eingehende Requests blind vertraut werden. Denn jede öffentlich erreichbare URL kann grundsätzlich von jedem aufgerufen werden.
Damit Webhooks nicht zum Sicherheitsproblem werden, braucht es ein klares Prüf-Schema: Ist der Absender echt? Ist die Nachricht unverändert? Ist sie frisch? Und wurde sie nicht einfach wiederholt (Replay)? Genau darum geht es hier – ohne Magie, aber mit praxistauglichen Bausteinen.
Warum Webhook-Requests nicht automatisch vertrauenswürdig sind
Typische Angriffe und Pannen im Alltag
Ein Webhook sieht für das Backend wie ein normaler HTTP-Request aus. Ohne zusätzliche Prüfungen kann ein Angreifer denselben Endpunkt mit eigenen Daten aufrufen – und so Prozesse auslösen, die eigentlich nur vom Zahlungsanbieter, CRM oder Shop-System kommen sollten.
Häufige Probleme:
- Ein fremder Request löst „Bestellung bezahlt“ aus, obwohl keine Zahlung existiert.
- Ein gültiger Request wird später erneut geschickt (Replay) und löst die Aktion doppelt aus.
- Ein Proxy oder eine Middleware verändert unabsichtlich den Body, wodurch Signaturen später nicht mehr passen.
- Das Backend akzeptiert Requests ohne Prüfung, weil „die URL ja geheim ist“.
„Geheime URL“ ist kein Sicherheitskonzept
Eine schwer erratbare URL hilft höchstens gegen Zufallstreffer, aber nicht gegen Logs, Fehlkonfigurationen, Leaks oder gezieltes Scanning. Sicherheit muss auf überprüfbaren Merkmalen beruhen, nicht auf Hoffnung.
Signaturen prüfen: der wichtigste Baustein
Was eine Signatur leistet (einfach erklärt)
Bei einer Signatur berechnet der Sender aus dem Request (meist aus dem Body, manchmal auch aus ausgewählten Headern) einen kryptografischen Prüfwert und sendet ihn im Header mit. Das Backend berechnet denselben Wert mit einem gemeinsamen Geheimnis erneut. Stimmen beide Werte überein, ist sehr wahrscheinlich: Der Request kommt von jemandem, der das Geheimnis kennt – und der Body wurde unterwegs nicht verändert.
Zentral ist dabei fast immer ein HMAC (Hash-based Message Authentication Code). Der konkrete Algorithmus (z. B. SHA-256) hängt vom Anbieter ab, die Idee bleibt gleich.
Worauf bei der Implementierung geachtet werden muss
- Raw Body verwenden: Die Signatur bezieht sich in der Regel auf den unveränderten Request-Body. Sobald JSON automatisch neu serialisiert wird (andere Leerzeichen, andere Reihenfolge), stimmt die Signatur nicht mehr.
- Header-Namen und -Format exakt umsetzen: Viele Anbieter nutzen z. B. ein Schema wie Webhook-Signatur oder ein Präfix (z. B. „sha256=…“). Das Format muss 1:1 geparst werden.
- Timing-sicher vergleichen: Der Vergleich sollte nicht vorzeitig abbrechen (sonst sind Timing-Angriffe leichter). Viele Sprachen bieten dafür einen „constant time compare“.
- Secrets rotieren können: Das Backend sollte kurzzeitig mehrere Secrets akzeptieren (alt/neu), damit eine Rotation ohne Downtime möglich ist.
Mini-Fallbeispiel: Warum „JSON parsen und wieder stringify“ scheitern kann
Ein Anbieter signiert den Body exakt so, wie er gesendet wird. Das Backend parst JSON, speichert es als Objekt und wandelt es wieder in JSON um, bevor es die Signatur prüft. Obwohl die Daten „gleich“ aussehen, kann der String anders sein (z. B. andere Escape-Sequenzen, andere Leerzeichen). Ergebnis: Signatur ungültig, obwohl der Request echt war. Deshalb immer zuerst den Raw Body für die Signaturprüfung sichern und erst danach JSON parsen.
Replay-Schutz: doppelte Zustellungen sauber abfangen
Warum Replays auch ohne Angreifer vorkommen
Viele Anbieter liefern Webhooks „mindestens einmal“ aus. Das bedeutet: Kommt keine schnelle Bestätigung zurück oder gab es einen Timeout, wird der gleiche Event erneut gesendet. Das ist normal und muss einkalkuliert werden.
Ohne Replay-Schutz kann ein zweiter identischer Request dann dieselbe Aktion erneut auslösen – etwa eine zweite Gutschrift, eine doppelte E-Mail oder eine doppelte Statusänderung.
Idempotenz über Event-IDs (praktisch und robust)
Die einfachste Strategie: Jeder Webhook enthält eine eindeutige Event-ID. Diese wird beim Verarbeiten gespeichert. Kommt die gleiche ID erneut, wird der Request als „bereits verarbeitet“ erkannt und nur noch bestätigt, ohne die Aktion nochmal auszuführen.
Damit das zuverlässig ist:
- Event-ID in einer Datenbank-Tabelle mit Unique-Constraint speichern (so entstehen keine Race-Conditions).
- Eine sinnvolle Aufbewahrungszeit festlegen (z. B. so lange, wie Retries realistisch sind).
- Immer die gleiche Event-ID verwenden, nicht aus dem Payload selbst „zusammenbasteln“.
Wer dieses Prinzip grundlegend einordnen möchte, findet dazu passend: Idempotency Keys in APIs verständlich erklärt.
Zeitfenster mit Timestamp + Nonce kombinieren
Wenn ein Anbieter einen Timestamp mitsendet, lässt sich ein Zeitfenster prüfen (z. B. „nicht älter als X Minuten“ – die konkrete Grenze hängt vom System ab). Für stärkeren Schutz kann zusätzlich eine Nonce (ein zufälliger Einmalwert) verwendet werden, die ebenfalls gespeichert und nur einmal akzeptiert wird.
Wichtig: Ein Timestamp alleine verhindert keinen Replay innerhalb des Zeitfensters. Dafür braucht es Event-ID oder Nonce als „Einmal-Merkmal“.
Request-Handling im Backend: Reihenfolge und Fehlerfälle
Empfohlene Prüf-Reihenfolge
Die Reihenfolge ist wichtig, damit einerseits nichts Unnötiges verarbeitet wird und andererseits die Signaturprüfung korrekt bleibt:
- Request entgegennehmen und Raw Body unverändert sichern.
- Signatur aus Header lesen und gegen den Raw Body prüfen.
- Timestamp/Zeitrahmen prüfen (falls vorhanden).
- Payload parsen und Event-ID extrahieren.
- Replay prüfen (Event-ID/Nonce).
- Business-Logik ausführen und Ergebnis speichern.
- Antwort an den Anbieter senden.
Welche HTTP-Antworten sinnvoll sind
Viele Anbieter werten jede 2xx-Antwort als „erfolgreich zugestellt“. Alles andere führt zu Retries. Deshalb ist es wichtig, bewusst zu entscheiden, wann wirklich ein Fehler zurückgegeben wird.
| Situation | Empfehlung |
|---|---|
| Signatur ungültig | 4xx senden und Verarbeitung abbrechen |
| Event bereits verarbeitet | 2xx senden (bestätigen), keine Aktion erneut ausführen |
| Temporärer DB-Fehler | 5xx senden, damit Retry möglich ist |
| Payload semantisch unbrauchbar (z. B. Pflichtfeld fehlt) | 4xx senden; zusätzlich Logging/Monitoring |
Wer mit Statuscodes sicher umgehen will, kann das Thema hier vertiefen: HTTP Statuscodes verstehen.
Kurze Umsetzungsschritte für ein belastbares Setup
- Webhook-Endpunkt als eigenen Controller/Route behandeln, nicht „irgendwo nebenbei“.
- Webhook-Secret pro Provider getrennt speichern und regelmäßig rotieren.
- Raw Body abgreifen, bevor Frameworks JSON automatisch parsen oder verändern.
- Signatur strikt prüfen (inklusive konstantem Vergleich) und bei Fehlern sofort abbrechen.
- Event-ID/Nonce speichern und doppelte Zustellungen idempotent behandeln.
- Antwortlogik definieren: Wann 2xx, wann 4xx, wann 5xx – und warum.
- Logs strukturieren (Request-ID, Event-ID, Provider, Ergebnis), damit Fehler schnell auffindbar sind.
Häufige Stolpersteine in Frameworks und Proxys
Body-Parsing und Middleware: der Klassiker
In vielen Setups liest eine Middleware den Request-Body bereits aus (z. B. für Logging oder Parsing). Danach ist der Stream „verbraucht“ und der Controller bekommt keinen identischen Raw Body mehr. Ergebnis: Signaturprüfung schlägt fehl oder wird aus Versehen übersprungen.
Lösung: Den Raw Body an einer zentralen Stelle einmal lesen, zwischenspeichern und sowohl für die Signaturprüfung als auch fürs Parsing verwenden.
Reverse Proxies und Encodings
Ein Reverse Proxy verändert normalerweise nicht den Body. Probleme entstehen eher durch falsche Content-Encoding/Transfer-Encoding-Behandlung oder durch zusätzliche Sicherheitslayer, die Requests „normalisieren“. Wenn Signaturen plötzlich sporadisch ungültig sind, lohnt sich ein Blick auf:
- ob der Provider komprimiert sendet und der Proxy entpackt (oder umgekehrt),
- ob Zeilenumbrüche oder Character-Encoding unerwartet geändert werden,
- ob ein WAF (Web Application Firewall) Bodies modifiziert.
Entscheidungshilfe: Welche Schutzkombination passt?
- Wenn der Anbieter Signaturen anbietet:
- Signatur + Event-ID ist in den meisten Fällen die beste Basis.
- Zusätzlich Timestamp prüfen, wenn er mit signiert ist (dann ist er manipulationssicher).
- Wenn nur ein „Token im Header“ möglich ist:
- Token ist besser als nichts, ersetzt aber keine Integritätsprüfung des Bodys.
- Replay-Schutz über Event-ID wird dann besonders wichtig.
- Wenn weder Signatur noch Token vorhanden sind:
- IP-Allowlisting kann helfen, ist aber fehleranfällig (IP-Wechsel) und kein alleiniger Schutz.
- In diesem Fall sollte mindestens Idempotenz + Monitoring sehr konsequent umgesetzt werden.
Logging und Monitoring: Sicherheit endet nicht beim Prüfen
Was in Logs stehen sollte (ohne sensible Daten zu leaken)
Logs sind oft der Unterschied zwischen „Fehler gefunden“ und „stundenlanges Rätselraten“. Gleichzeitig dürfen Secrets und komplette Payloads (z. B. personenbezogene Daten) nicht leichtfertig geloggt werden.
Sinnvolle Log-Felder:
- Provider-Name
- Event-ID
- Ergebnis der Signaturprüfung (true/false)
- Entscheidung Replay (neu/bereits verarbeitet)
- HTTP-Status der Antwort
- Interne Request-ID/Correlation-ID
Für eine gute, durchsuchbare Struktur passt thematisch: Structured Logging im Backend.
Alarmierung bei Signaturfehlern
Viele ungültige Signaturen in kurzer Zeit sind ein starkes Signal (Fehlkonfiguration oder Angriff). Hier lohnt sich eine einfache Alarmregel im Monitoring: Rate von 4xx am Webhook-Endpunkt und Anteil „Signatur ungültig“.
Kurze Fragen aus der Praxis
Muss TLS/HTTPS reichen?
HTTPS schützt die Verbindung auf dem Transportweg, aber nicht davor, dass jemand direkt selbst Requests an den Endpunkt sendet. Für „echten Absender“ und „unverändert“ braucht es Signaturen oder vergleichbare Mechanismen.
Kann ein Webhook trotzdem doppelt kommen, obwohl alles korrekt ist?
Ja. Retries sind üblich. Deshalb ist Idempotenz (doppelte Events schadlos machen) ein Feature, kein Fehler.
Kann die Signaturprüfung nach dem JSON-Parsing stattfinden?
In der Regel nein, weil viele Signaturen auf dem exakten Raw Body basieren. Sicher ist: Raw Body zuerst sichern und prüfen, dann parsen.
Quellen
- —

