Webhooks erklärt: Signierte Payloads und Retry-Logik
Sie haben gerade ein Zahlungs-Gateway integriert. Die Dokumentation besagt: "Wir senden einen Webhook, wenn eine Zahlung erfolgreich ist." Großartig. Aber dann fragen Sie sich: Woher weiß ich, dass die Anfrage wirklich von ihnen kam? Was, wenn mein Server down ist, wenn sie ihn senden? Was, wenn sie dasselbe Event zweimal senden?
Webhooks sind leistungsstark, aber mit Fallstricken verbunden. Dieser Leitfaden behandelt die Mechanik, Sicherheit und Zuverlässigkeitsmuster, die Sie benötigen, um sie korrekt zu handhaben.
Was ist ein Webhook?
Ein Webhook ist eine HTTP-POST-Anfrage, die ein System an ein anderes sendet, wenn ein bestimmtes Ereignis eintritt. Anstatt dass Ihre App alle paar Sekunden eine API abfragt ("Gibt es neue Bestellungen? Gibt es neue Bestellungen?"), pusht der Anbieter Daten zu Ihnen, sobald etwas passiert.
Typischer Ablauf:
- Sie registrieren eine URL (z. B.
https://yourapp.com/webhooks/payments) beim Anbieter. - Ein Ereignis tritt ein (Zahlung erfolgreich, Benutzer registriert, Datei hochgeladen).
- Der Anbieter sendet eine POST-Anfrage an Ihre URL mit einem JSON-Body, der das Ereignis beschreibt.
- Ihr Server verarbeitet das Ereignis und antwortet mit
2xx, um den Empfang zu bestätigen.
Wenn Sie nicht schnell antworten (normalerweise innerhalb von 5–30 Sekunden), betrachtet der Anbieter die Zustellung als fehlgeschlagen und versucht es möglicherweise erneut.
Warum Sie signierte Payloads verifizieren müssen
Ihr Webhook-Endpunkt ist öffentlich zugänglich. Jeder, der die URL entdeckt, kann gefälschte Ereignisse senden. Ohne Verifizierung könnte ein Angreifer ein "Zahlung erfolgreich"-Ereignis fälschen und kostenlose Waren erhalten.
Die Lösung: signierte Payloads. Der Anbieter berechnet eine kryptografische Signatur über den Request-Body unter Verwendung eines gemeinsamen Geheimnisses (nur Ihnen und ihm bekannt) und fügt sie in einen Header ein. Sie berechnen die Signatur auf Ihrer Seite neu und vergleichen sie.
Wie HMAC-Signierung funktioniert
Die meisten Anbieter verwenden HMAC-SHA256. Die Schritte:
- Der Anbieter verkettet den rohen Request-Body mit einem Zeitstempel (um Replay-Angriffe zu verhindern).
- Der Anbieter berechnet
HMAC-SHA256(secret, timestamp + '.' + body). - Der Anbieter sendet die Signatur in einem Header, z. B.
X-Signature: t=1234567890,v1=abc123.... - Sie extrahieren den Zeitstempel und die Signatur, berechnen den HMAC mit Ihrer Kopie des Geheimnisses neu und vergleichen ihn mit einer zeitkonstanten Vergleichsfunktion.
Hier ist ein minimales Node.js-Beispiel:
const crypto = require('crypto');
function verifySignature(req, secret) {
const signatureHeader = req.headers['x-signature'];
const [tPart, vPart] = signatureHeader.split(',');
const timestamp = tPart.split('=')[1];
const receivedSig = vPart.split('=')[1];
const payload = timestamp + '.' + JSON.stringify(req.body);
const expectedSig = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
// Zeitkonstanter Vergleich zur Verhinderung von Timing-Angriffen
return crypto.timingSafeEqual(
Buffer.from(receivedSig, 'hex'),
Buffer.from(expectedSig, 'hex')
);
}
Wichtig: Verwenden Sie immer den rohen Request-Body für die Signaturverifizierung. Wenn Ihr Framework JSON parst und neu serialisiert, kann die Byte-Sequenz abweichen, was zu einem Verifizierungsfehler führt. Erfassen Sie den rohen Body vor dem Parsen.
Zeitstempel-Validierung
Überprüfen Sie, ob der Zeitstempel aktuell ist (z. B. innerhalb von 5 Minuten). Dies verhindert Replay-Angriffe, bei denen ein Angreifer eine gültige Anfrage abfängt und später erneut sendet.
Retry-Logik: Fehler elegant behandeln
Ihr Server könnte down, überlastet sein oder eine Netzwerkstörung haben. Anbieter handhaben dies, indem sie fehlgeschlagene Zustellungen erneut versuchen. Aber Sie müssen Ihren Endpunkt so gestalten, dass er Wiederholungsversuche sicher verarbeitet.
Exponentielles Backoff mit Jitter
Anbieter versuchen es typischerweise mit zunehmenden Verzögerungen erneut: 1 Minute, 5 Minuten, 30 Minuten, 2 Stunden usw. Dies wird als exponentielles Backoff bezeichnet. Einige fügen zufälligen Jitter hinzu, um Thundering-Herd-Probleme zu vermeiden.
Von Ihrer Seite aus kontrollieren Sie nicht den Wiederholungsplan des Anbieters, aber Sie sollten:
- Mit
2xxantworten, sobald Sie das Ereignis sicher gespeichert haben (auch wenn die Verarbeitung asynchron erfolgt). 4xxfür dauerhafte Fehler zurückgeben (z. B. fehlerhafte Payload), damit der Anbieter aufhört, es erneut zu versuchen.5xxfür vorübergehende Fehler zurückgeben (z. B. Datenbank down), um Wiederholungsversuche auszulösen.
Idempotenz: Der Schlüssel zu sicheren Wiederholungsversuchen
Wiederholungsversuche bedeuten, dass Sie dasselbe Ereignis möglicherweise mehrmals empfangen. Ihre Verarbeitung muss idempotent sein – dasselbe Ereignis zweimal zu verarbeiten sollte die gleiche Wirkung haben wie einmal.
Üblicher Ansatz: Fügen Sie eine eindeutige Event-ID in die Payload ein. Prüfen Sie vor der Verarbeitung, ob Sie diese ID bereits behandelt haben. Wenn ja, geben Sie 200 zurück und überspringen Sie die Verarbeitung.
async function handleWebhook(event) {
const existing = await db.events.findOne({ id: event.id });
if (existing) {
return { status: 200, body: 'Already processed' };
}
await db.events.insert({ id: event.id, processedAt: new Date() });
await processEvent(event);
return { status: 200, body: 'OK' };
}
Dieses Muster stellt sicher, dass Sie, selbst wenn der Anbieter das Ereignis dreimal sendet, nur einmal handeln.
Vergleich: Polling vs. Webhooks
| Aspekt | Polling | Webhooks |
|---|---|---|
| Latenz | Abhängig vom Intervall (z. B. 30s) | Nahezu Echtzeit |
| Serverlast | Konstant, auch wenn keine Ereignisse auftreten | Nur wenn Ereignisse auftreten |
| Komplexität | Einfach zu implementieren | Erfordert Endpunkt, Verifizierung, Wiederholungsversuche |
| Zuverlässigkeit | Sie kontrollieren Wiederholungsversuche | Abhängig von der Wiederholungsrichtlinie des Anbieters |
Webhooks gewinnen bei Echtzeit-Updates, aber Polling kann ein Fallback für kritische Ereignisse sein, wenn Sie besorgt über verpasste Zustellungen sind.
Checkliste für Best Practices
- Verifizieren Sie immer Signaturen. Vertrauen Sie niemals einem unverifizierten Webhook.
- Verwenden Sie HTTPS. Webhook-Payloads enthalten oft sensible Daten.
- Antworten Sie schnell. Bestätigen Sie den Empfang schnell und verarbeiten Sie dann asynchron, falls nötig.
- Implementieren Sie Idempotenz. Speichern Sie Event-IDs, um doppelte Verarbeitung zu vermeiden.
- Protokollieren Sie alles. Führen Sie ein Protokoll der empfangenen Ereignisse für Debugging und Auditing.
- Überwachen Sie Fehler. Richten Sie Warnungen für wiederholte 5xx-Antworten oder Signaturverifizierungsfehler ein.
- Testen Sie mit echten Payloads. Verwenden Sie den Testmodus des Anbieters oder senden Sie Beispielereignisse an Ihren Endpunkt.
Debuggen von Webhook-Problemen
Wenn Webhooks fehlschlagen, ist der erste Schritt, die rohe Anfrage zu inspizieren. Häufige Probleme:
- Signatur-Nichtübereinstimmung: Sie verwenden den geparsten Body anstelle des rohen. Beheben Sie dies, indem Sie den rohen Body erfassen.
- Timeout: Ihr Endpunkt braucht zu lange zum Antworten. Verschieben Sie schwere Verarbeitung in einen Hintergrundjob.
- Fehlende Ereignisse: Überprüfen Sie das Dashboard des Anbieters auf Zustellungsprotokolle und Wiederholungsverlauf.
Wenn Sie HTTP-Traffic debuggen, können Tools wie Nginx Log Analyzer Ihnen helfen, Muster bei Anfragefehlern und Antwortcodes zu erkennen.
FAQ
Was ist ein Webhook-Secret und wie speichere ich es?
Das Secret ist ein gemeinsamer Schlüssel, der zum Signieren von Payloads verwendet wird. Speichern Sie es in Umgebungsvariablen oder einem Secrets Manager – niemals im Code oder in der Versionskontrolle. Rotieren Sie es regelmäßig, wenn der Anbieter dies unterstützt.
Wie oft wird ein Anbieter einen fehlgeschlagenen Webhook erneut versuchen?
Dies variiert je nach Anbieter. Einige versuchen es 24 Stunden lang mit exponentiellem Backoff erneut, andere 3 Tage. Überprüfen Sie die Dokumentation Ihres Anbieters für den genauen Zeitplan und die maximalen Versuche.
Kann ich Webhooks mit serverlosen Funktionen verwenden?
Ja, aber beachten Sie die Ausführungszeitlimits. Bestätigen Sie den Webhook schnell (geben Sie 200 zurück) und lagern Sie schwere Verarbeitung in eine Warteschlange oder Hintergrundfunktion aus, um Timeouts zu vermeiden.
Bereit, robuste Webhook-Integrationen zu erstellen? Beginnen Sie mit der Verifizierung von Signaturen und der Implementierung von Idempotenz – diese beiden Schritte sparen Ihnen Stunden beim Debuggen und verhindern kostspielige Sicherheitsvorfälle.