Webhooks erklärt: Signierte Payloads und Retry-Logik
Sie haben eine API erstellt und müssen nun andere Dienste benachrichtigen, wenn Ereignisse auftreten. Polling ist ineffizient, also greifen Sie zu Webhooks. Aber bald stellen Sie fest, dass Webhooks fehlschlagen, gefälscht werden oder doppelte Verarbeitung verursachen können. Dieser Artikel erklärt, wie Sie Webhooks mit signierten Payloads absichern und eine robuste Retry-Logik implementieren.
Was sind Webhooks?
Webhooks sind benutzerdefinierte HTTP-Callbacks. Wenn ein Ereignis in Ihrem System auftritt (z. B. eine Zahlung erfolgreich ist), senden Sie eine HTTP-POST-Anfrage an eine vom Abonnenten bereitgestellte URL. Die Payload enthält typischerweise Ereignisdaten im JSON- oder Formularformat.
Webhooks ermöglichen Echtzeitkommunikation zwischen Diensten ohne ständiges Polling. Sie werden häufig von Zahlungs-Gateways, CI/CD-Tools und SaaS-Plattformen verwendet.
Warum Webhooks absichern?
Ohne Sicherheit kann jeder, der die Webhook-URL kennt, gefälschte Anfragen senden, was zu Datenkorruption oder Betrug führt. Außerdem könnten Angreifer alte Anfragen wiederholen. Das Signieren von Payloads mit einem gemeinsamen Secret gewährleistet Authentizität und Integrität.
Payloads mit HMAC signieren
HMAC (Hash-based Message Authentication Code) ist eine gängige Methode zum Signieren von Webhooks. Sender und Empfänger teilen einen geheimen Schlüssel. Der Sender berechnet einen HMAC der Payload mit dem Secret und fügt ihn in einen Header ein (z. B. X-Signature). Der Empfänger berechnet den HMAC neu und vergleicht ihn.
Schritt für Schritt: Einen signierten Webhook senden
- Erstellen Sie die Payload (JSON).
- Berechnen Sie den HMAC-SHA256 der Payload mit dem Secret.
- Fügen Sie den Hex-Digest in einen Header ein, z. B.
X-Signature: sha256=.... - Senden Sie die POST-Anfrage.
// Node.js-Beispiel mit crypto
const crypto = require('crypto');
const secret = 'your_shared_secret';
const payload = JSON.stringify({ event: 'payment.success', amount: 100 });
const signature = crypto.createHmac('sha256', secret).update(payload).digest('hex');
// POST mit Header X-Signature: sha256=signature senden
Die Signatur verifizieren
Auf der Empfängerseite extrahieren Sie den Signatur-Header, berechnen den HMAC des rohen Request-Bodys und vergleichen ihn mit einem konstantzeitigen Vergleich, um Timing-Angriffe zu verhindern.
// Express.js-Beispiel
app.post('/webhook', (req, res) => {
const signature = req.headers['x-signature'];
const computed = crypto.createHmac('sha256', secret).update(req.rawBody).digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(computed))) {
return res.status(401).send('Invalid signature');
}
// Payload verarbeiten
res.status(200).send('OK');
});
Hinweis: Stellen Sie sicher, dass Sie den rohen Body verwenden, nicht das geparste JSON, da das Parsen die Payload verändern kann.
Replay-Angriffe verhindern
Fügen Sie einen Zeitstempel in die signierte Payload ein und lehnen Sie Anfragen ab, die älter als ein paar Minuten sind. Fügen Sie außerdem eine eindeutige Ereignis-ID hinzu und speichern Sie verarbeitete IDs, um Duplikate zu vermeiden.
Retry-Logik für zuverlässige Zustellung
Webhook-Endpunkte können ausgefallen oder langsam sein. Implementieren Sie Wiederholungsversuche mit exponentiellem Backoff und Jitter. Legen Sie eine maximale Anzahl von Wiederholungen fest (z. B. 5) und ein Timeout für jede Anfrage.
Retry-Strategie
- Exponentielles Backoff: Warten Sie 1s, 2s, 4s, 8s usw.
- Jitter: Fügen Sie Zufälligkeit hinzu, um einen Thundering-Herd zu vermeiden.
- Idempotenz: Verwenden Sie einen Idempotenzschlüssel, damit doppelte Zustellungen keine doppelten Aktionen verursachen.
Beispiel für einen Wiederholungsplan: 1. Wiederholung nach 5s, 2. nach 30s, 3. nach 2min, 4. nach 10min, 5. nach 1h.
Fehler behandeln
Wenn alle Wiederholungen fehlschlagen, protokollieren Sie den Fehler und benachrichtigen Sie den Abonnenten (z. B. per E-Mail oder Dashboard). Bieten Sie eine Möglichkeit, Webhooks manuell erneut zu senden.
Vergleich: Signierte Payloads vs. Basic Auth
| Methode | Sicherheit | Komplexität | Replay-Schutz |
|---|---|---|---|
| HMAC-signierte Payload | Hoch | Mittel | Ja (mit Zeitstempel) |
| Basic Auth | Niedrig | Niedrig | Nein |
| API-Schlüssel im Header | Mittel | Niedrig | Nein |
Best Practices
- Verwenden Sie immer HTTPS für Webhook-Endpunkte.
- Rotieren Sie Secrets regelmäßig.
- Validieren Sie das Payload-Schema, bevor Sie es verarbeiten.
- Antworten Sie schnell (innerhalb von 2xx) und verarbeiten Sie asynchron.
- Überwachen Sie Webhook-Zustellmetriken (Erfolgsrate, Latenz).
FAQ
Wie verifiziere ich eine Webhook-Signatur?
Berechnen Sie den HMAC des rohen Request-Bodys mit Ihrem Secret und vergleichen Sie ihn mit dem Signatur-Header unter Verwendung eines konstantzeitigen Vergleichs.
Was sollte ich tun, wenn ein Webhook fehlschlägt?
Implementieren Sie Wiederholungsversuche mit exponentiellem Backoff und Jitter. Wenn alle Wiederholungen fehlschlagen, protokollieren Sie den Fehler und bieten Sie eine manuelle erneute Sendung an.
Kann ich Webhooks ohne Signierung verwenden?
Es wird nicht empfohlen. Ohne Signierung können Sie den Absender nicht verifizieren, was Ihr System anfällig für Spoofing- und Replay-Angriffe macht.
Beim Testen von Webhook-Payloads müssen Sie möglicherweise JSON-Antworten inspizieren. Verwenden Sie unseren JSON Formatter, um JSON-Daten schnell zu formatieren und zu validieren.