Webhooks erklärt: Signierte Payloads und Retries
Warum Webhooks signierte Payloads und Retries benötigen
Sie haben gerade einen Drittanbieterdienst integriert, der Webhooks an Ihren Endpunkt sendet. Im Test funktioniert alles, aber in der Produktion stellen Sie fest, dass Ereignisse fehlen, doppelte Zustellungen auftreten und – schlimmer noch – jemand Anfragen an Ihre Webhook-URL fälscht. Ohne geeignete Sicherheits- und Zuverlässigkeitsmaßnahmen können Webhooks zu einer Quelle von Fehlern und Sicherheitslücken werden.
Webhooks sind HTTP-Callbacks, die Ihre Anwendung benachrichtigen, wenn ein Ereignis eintritt. Das Konzept ist einfach, aber in der Praxis schwierig, weil sie Vertrauensgrenzen und Netzwerkzuverlässigkeitsprobleme überschreiten. In diesem Leitfaden behandeln wir zwei kritische Aspekte: signierte Payloads zur Überprüfung der Authentizität und Retries zur Sicherstellung der Zustellung. Wir gehen auf praktische Implementierungen ein, die Sie sofort anwenden können.
Signierte Payloads verstehen
Ein signierter Payload ist eine Möglichkeit für den Absender zu beweisen, dass der Webhook von ihm stammt und nicht manipuliert wurde. Der Absender berechnet eine kryptografische Signatur über den Request-Body (und manchmal auch über Header) unter Verwendung eines gemeinsamen Geheimnisses und fügt diese Signatur in einen Header ein. Ihr Endpunkt berechnet die Signatur neu und vergleicht sie.
Der gebräuchlichste Algorithmus ist HMAC-SHA256. Er ist schnell, sicher und weit verbreitet. So funktioniert es:
- Absender und Empfänger teilen einen geheimen Schlüssel (konfiguriert in den Webhook-Einstellungen).
- Für jeden Webhook erstellt der Absender eine Signatur, indem er den Payload mit dem Geheimnis unter Verwendung von HMAC-SHA256 hasht.
- Die Signatur wird in einem Header wie
X-Signaturegesendet. - Der Empfänger berechnet denselben HMAC und vergleicht ihn mit einem konstantzeitigen Vergleich, um Timing-Angriffe zu verhindern.
HMAC-Verifizierung in Node.js implementieren
Sehen wir uns ein konkretes Beispiel an. Angenommen, der Absender fügt die Signatur als Hex-String in X-Signature ein. So überprüfen Sie sie in einer Express-Route:
const crypto = require('crypto');
const express = require('express');
const app = express();
// Rohen Body für die Signaturprüfung verwenden
app.use('/webhook', express.raw({ type: 'application/json' }));
app.post('/webhook', (req, res) => {
const signature = req.headers['x-signature'];
const secret = process.env.WEBHOOK_SECRET;
const expected = crypto
.createHmac('sha256', secret)
.update(req.body)
.digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
return res.status(401).send('Invalid signature');
}
// Ereignis verarbeiten
const event = JSON.parse(req.body);
console.log('Received event:', event.type);
res.status(200).send('OK');
});
app.listen(3000);
Wichtig: Verwenden Sie für die Signaturberechnung immer den rohen Request-Body, nicht das geparste JSON. Das Parsen und erneute Serialisieren kann Leerzeichen und Reihenfolge ändern und die Signatur brechen.
Zeitstempel- und Replay-Schutz
Signaturen allein verhindern keine Replay-Angriffe. Ein Angreifer könnte eine gültige signierte Anfrage abfangen und später erneut senden. Um dies zu mildern, fügen Sie einen Zeitstempel in den signierten Payload oder in einen Header ein. Fügen Sie beispielsweise einen X-Timestamp-Header mit der Unix-Zeit hinzu. Der Empfänger prüft, ob der Zeitstempel innerhalb eines Toleranzfensters (z. B. 5 Minuten) liegt, und lehnt ältere Anfragen ab.
Fügen Sie den Zeitstempel auch in die Signaturberechnung ein, um Manipulationen zu verhindern. Der Absender berechnet HMAC über timestamp + '.' + body. Der Empfänger macht dasselbe und vergleicht.
Retries für zuverlässige Zustellung implementieren
Webhooks reisen über das öffentliche Internet, daher sind Fehler unvermeidlich: Netzwerk-Timeouts, Serverfehler (5xx) oder Ihr Endpunkt ist vorübergehend nicht erreichbar. Ein robustes Webhook-System muss fehlgeschlagene Zustellungen wiederholen.
Retry-Strategien
Übliche Retry-Strategien sind:
- Feste Verzögerung: Wiederholung nach einem festen Intervall (z. B. 1 Minute). Einfach, kann aber bei vielen Fehlern überlasten.
- Exponentielles Backoff: Längere Wartezeit nach jedem Versuch (z. B. 1s, 2s, 4s, 8s...). Dies ist der gebräuchlichste und empfohlene Ansatz.
- Jitter: Fügen Sie der Verzögerung Zufälligkeit hinzu, um Thundering-Herd-Probleme zu vermeiden, wenn viele Webhooks gleichzeitig fehlschlagen.
Eine typische Richtlinie könnte sein: bis zu 5 Wiederholungen mit exponentiellem Backoff und Jitter, beginnend bei 10 Sekunden. Danach markieren Sie die Zustellung als fehlgeschlagen und benachrichtigen möglicherweise.
Idempotenz: Umgang mit Duplikaten
Retries können zu doppelten Zustellungen führen. Ihr Endpunkt muss idempotent sein – die zweimalige Verarbeitung desselben Ereignisses sollte keine Nebenwirkungen wie doppelte Abbuchungen beim Kunden verursachen. Fügen Sie eine eindeutige Ereignis-ID in den Payload ein (z. B. event.id) und speichern Sie verarbeitete IDs für einen angemessenen Zeitraum. Prüfen Sie vor der Verarbeitung, ob die ID bereits gesehen wurde.
Alternativ können Sie Ihre Operationen natürlich idempotent gestalten (z. B. Upserts anstelle von Inserts verwenden).
Schnelle Antwort
Ihr Webhook-Endpunkt sollte den Empfang schnell bestätigen (innerhalb weniger Sekunden) und das Ereignis asynchron verarbeiten. Wenn die Verarbeitung zu lange dauert, kann der Absender ein Timeout bekommen und erneut versuchen, was zu Duplikaten führt. Verwenden Sie eine Warteschlange: Antworten Sie mit 200 OK sofort nach der Signaturprüfung und stellen Sie das Ereignis dann für die Hintergrundverarbeitung in die Warteschlange.
Vergleich der Webhook-Sicherheitsmaßnahmen
| Maßnahme | Zweck | Implementierungskomplexität |
|---|---|---|
| HMAC-Signatur | Authentizität und Integrität überprüfen | Niedrig |
| Zeitstempelvalidierung | Replay-Angriffe verhindern | Niedrig |
| Idempotenzschlüssel | Doppelte Verarbeitung vermeiden | Mittel |
| IP-Allowlisting | Auf bekannte Absender-IPs beschränken | Niedrig (aber unflexibel) |
| HTTPS | Daten während der Übertragung verschlüsseln | Niedrig |
IP-Allowlisting kann eine zusätzliche Ebene bieten, ist aber nicht zuverlässig, da sich Absender-IPs ändern können. Verlassen Sie sich hauptsächlich auf Signaturen.
Testen Ihres Webhook-Endpunkts
Verwenden Sie Tools wie ngrok, um Ihren lokalen Server verfügbar zu machen und Test-Webhooks vom Dashboard des Anbieters auszulösen. Überprüfen Sie, ob Signaturen korrekt validiert werden und ob Retries funktionieren, indem Sie Fehler simulieren (z. B. bei den ersten Versuchen 500 zurückgeben).
Beim Debuggen müssen Sie möglicherweise JSON-Payloads inspizieren. Der JSON Formatter kann Ihnen helfen, Webhook-Payloads schnell übersichtlich zu formatieren und zu validieren.
FAQ
Was ist ein signierter Webhook-Payload?
Ein signierter Payload enthält eine kryptografische Signatur (normalerweise HMAC), die es dem Empfänger ermöglicht zu überprüfen, dass die Anfrage vom erwarteten Absender stammt und nicht verändert wurde. Sie wird mit einem gemeinsamen Geheimnis berechnet.
Wie oft sollte ich einen fehlgeschlagenen Webhook wiederholen?
Es gibt keine universelle Zahl, aber 3–5 Wiederholungen mit exponentiellem Backoff sind üblich. Danach protokollieren Sie den Fehler und ziehen eine Benachrichtigung in Betracht. Das Ziel ist, vorübergehende Probleme ohne unendliche Wiederholungen zu behandeln.
Kann ich JWT für Webhook-Signaturen verwenden?
Ja, einige Anbieter verwenden JWT (JSON Web Tokens) zum Signieren von Webhooks. Das Token enthält Claims und ist mit einem Geheimnis oder privaten Schlüssel signiert. Die Überprüfung ist ähnlich: Validieren Sie die Signatur und prüfen Sie Claims wie Ablaufzeit.
Bereit, sichere Webhooks zu implementieren? Beginnen Sie mit der Generierung eines starken Geheimnisses, fügen Sie HMAC-Verifizierung hinzu und richten Sie Retries mit Idempotenz ein. Für eine schnelle Payload-Inspektion während der Entwicklung probieren Sie unseren JSON Formatter zum Formatieren und Validieren von Webhook-JSON.