Während einer Bereitstellung kommt um 02:14 Uhr ein Zahlungs-Webhook an. Die App antwortet mit 503. Der Anbieter versucht es dreimal erneut. Am Morgen hat der Kunde drei aktive Abonnements und nur eine Rechnung. Niemand hatte Idempotenz implementiert – nur ein naives „INSERT“.
Webhooks sind keine „coolen HTTP-Callbacks“. Hierbei handelt es sich um mindestens einmalige Lieferungen mit Wiederholungsversuchen, nicht garantierter Reihenfolge und manchmal winzigen Verzögerungen.
Liefermodell
Gehen Sie mindestens einmal davon aus: normale Duplikate. Manchmal Nicht-FIFO-Reihenfolge zwischen Ereignistypen. Ihr Handler muss idempotent sein und eine logische Neuordnung tolerieren (z. B. „storniert“ vor „bezahlt“ ist selten, aber möglich).
Signatur und Zeitstempel
Überprüfen Sie HMAC-SHA256 mit drehbarem Geheimnis. Ablehnen, wenn Zeitstempel > 5 Min. (Wiedergabe). Zeitkonstante Vergleiche für die Signatur.
Protokollieren Sie Signaturfehler getrennt von den 500 Anwendungen – verwechseln Sie einen Angriff nicht mit einem Fehler.
Idempotenz in der Praxis
| Ansatz | Vorteil | Grenze |
|---|---|---|
| event_id in Basis | Einfach | TTL-Bereinigung |
| Idempotency-Key-Header | API-Standard | Variabler Support-Anbieter |
| Geschäftsstatus (paid_at) | Robustes Handwerk | Zuchtbedingungen |
Kombinieren Sie Anbieterschlüssel + SQL-Eindeutigkeitsbeschränkung.
HTTP- und asynchrone Antworten
Verarbeitung < 2 s: 200 Sync. Ansonsten 202 + Schwanz (Redis, SQS, Rabbit). Der Arbeiter nimmt event_id. Leisten Sie niemals schwere Arbeit, bevor Sie ohne Idempotenz freisprechen.
Warteschlange für unzustellbare Nachrichten für Geschäftsausfälle nach N Versuchen.
Beobachtbarkeit
Metriken: Handler-Latenz, 2xx/4xx/5xx-Rate, Warteschlangenverzögerung, übersprungene Duplikate. Korrelierte Trace-Ereignis-ID → Job → Rechnung. Runbook: „Manuelle Wiedergabe ohne Doppeleffekt“ dokumentiert.
Checkliste für die Endpunktproduktion
- [ ] HMAC-Signatur in konstanter Zeit verifiziert
- [ ] Zeitstempel-Anti-Wiedergabe (<5 Min.)
- [ ] Tabelle event_id eindeutige Einschränkung
- [ ] Antwort 2xx/202 < Timeout-Anbieter
- [ ] Asynchrone Warteschlange für Verarbeitung >2 s
- [ ] Dead Letter nach N geschäftlichen Misserfolgen
- [ ] Strukturierte Protokolle event_id + Latenz
- [ ] Idempotenz getestet (3 identische POSTs)
- [ ] Firewall-IP-Anbieter dokumentiert
- [ ] Runbook-Wiederholungshandbuch ohne Doppeleffekt
- [ ] Geplante Rotation des Webhook-Geheimnisses
- [ ] DSGVO: begrenzte Speicherung der Nutzdaten
Überprüfen Sie diese Liste, bevor Sie die öffentliche URL preisgeben – ein „fast guter“ Webhook kostet mehr als eine zweitägige Veröffentlichungsverzögerung.
Wiederholen Sie Szenarien und Vorfälle
Stellen Sie sich eine Bereitstellung vor, die PHP-FPM 30 Sekunden lang neu startet: Der Zahlungsanbieter sendet fünf Wiederholungsversuche. Ohne Idempotenztabelle schreiben Sie die gleiche Zahlung fünfmal gut. Der Kundensupport entdeckt den Fehler, bevor Ihre Anwendung protokolliert, da das Buchhaltungs-Dashboard Duplikate schneller aggregiert als Ihre technische Überwachung.
Eine legitime Wiederholung unterscheidet sich von einer böswilligen Wiederholung: Die erste kommt vom Anbieter nach einer Zeitüberschreitung, die zweite von einem Angreifer, der eine nicht signierte Webhook-URL erfasst (falls Sie HMAC vergessen haben). Die Signatur bindet den Körper an das Geheimnis; Ohne sie reicht es aus, einen erfassten POST abzuspielen.
Nutzen Sie für Tests das Replay-Tool des Anbieters (Stripe CLI, GitHub Redelivery) im Staging mit einer Einwegbasis. Stellen Sie sicher, dass der dritte identische Wiederholungsversuch nichts an der Basis ändert. Automatisieren Sie diesen Test in CI, wenn der Endpunkt kritisch ist.
Überprüfen Sie auf der Shared-Hosting-Seite „max_execution_time“ PHP- und Nginx-Proxy-Timeout – ein 504-Gateway generiert Wiederholungsversuche, selbst wenn Ihr Handler zwei Sekunden später fertig gewesen wäre. Timeouts ausrichten: Nginx > PHP > Provider-Webhook-Timeout, mit Marge.
Die Anbieter unterscheiden sich im Signatur-Header (Stripe-Signature,
Versionieren Sie das Webhook-Geheimnis als Passwort: Rotation mit doppeltem Geheimnis, das 24 Stunden lang aktiv ist, wenn der Anbieter dies unterstützt.
Auslastungstest: Simulieren Sie 10-fache Burst-Webhooks – Warteschlangentiefe und Größe der Worker-Anzahl vor dem Black Friday.
Führen Sie ein datiertes Runbook, Vorher-/Nachher-Kennzahlen und eine Überprüfung nach dem Vorfall – kumulative Disziplin vermeidet Panik am Freitagabend.
Führen Sie ein datiertes Runbook, Vorher-/Nachher-Kennzahlen und eine Überprüfung nach dem Vorfall – kumulative Disziplin vermeidet Panik am Freitagabend.
Gemeinsame Zeitüberschreitungen
Nginx > PHP > Timeout-Anbieter ausrichten – 504 löst Wiederholungsversuche aus.
Entscheide dich und gehe ohne blinden Fleck voran
- Überprüfen Sie die HMAC-Signatur in konstanter Zeit mit einem Anti-Replay-Zeitstempel von weniger als fünf Minuten.
- Deduplicate by event_id – eindeutige Einschränkung in der Basis, Idempotenz getestet mit drei identischen POSTs.
- Schnelle Antwort 2xx/202 – asynchrone Warteschlange, wenn die Verarbeitung zwei Sekunden überschreitet; Unzustellbarer Brief nach N geschäftlichen Misserfolgen.
- Dokumentanbieter-IPs – Firewall, Webhook-Secret-Rotation, manuelle Runbook-Wiedergabe ohne Doppeleffekt.
- Begrenzung der Payload-Aufbewahrung – DSGVO-Konformität bei gespeicherten Daten.
Um zuverlässiges API-Hosting (Latenz, SLA) auszuwählen, verwenden Sie den Vergleicher, das Verzeichnis und unsere Leitfäden Observability.
Häufig gestellte Fragen
Warum Webhooks signieren?
Die HMAC-Signatur beweist, dass die Leiche vom Anbieter stammt und während des Transports nicht verändert wurde. Ohne sie kann jeder an Ihren Endpunkt posten.
Welcher HTTP-Code für Wiederholungsversuche?
2xx freigesprochen. 4xx bei permanentem Fehler (ungültige Signatur) nicht wiederholbar. 5xx- oder Timeout-Trigger-Wiederholungsversuche – daher obligatorische Idempotenz.
Wie dedupliziert man?
Speichern Sie event_id (oder einen stabilen Hash) mit eindeutiger Einschränkung. Ignorieren Sie bereits verarbeitete Duplikate, auch wenn sich der Text geringfügig unterscheidet.
Timeout auf Senderseite?
Oftmals 5–30 Sek. Reagieren Sie schnell (202 + asynchroner Job), wenn die Verarbeitung lange dauert, garantieren Sie dann aber Idempotenz auf der Worker-Seite.
Simulieren Sie vor dem Öffnen des Endpunkts in prod drei identische POSTs – wenn sich die Datenbank dreimal ändert, sind Sie nicht bereit.
