Webhooks expliqués : signatures et stratégies de retry
Pourquoi les webhooks échouent et comment y remédier
Vous venez d'intégrer le webhook d'un fournisseur de paiement pour mettre à jour les statuts de commande dans votre application. Tout fonctionne en test, mais en production, certains événements n'arrivent jamais, ou pire, vous recevez des doublons. Sans protections adéquates, les webhooks peuvent devenir une source d'échecs silencieux et de failles de sécurité.
Les webhooks sont des callbacks HTTP déclenchés par des événements, mais contrairement aux appels API classiques, ils sont basés sur le push et asynchrones. Cela introduit deux défis majeurs : vérifier l'authenticité et garantir la livraison. Dans ce guide, nous aborderons les deux avec des signatures et des retries intelligents.
Que sont les webhooks ?
Un webhook est un callback HTTP défini par l'utilisateur. Lorsqu'un événement se produit dans un système source (par exemple, un nouveau paiement), il envoie une requête HTTP POST à une URL que vous fournissez, contenant les données de l'événement. Cela permet des réactions en temps réel sans interrogation répétée (polling).
Les cas d'usage courants incluent les notifications de paiement, les déclencheurs CI/CD et les intégrations de chat. Mais comme les webhooks traversent l'internet public, ils sont vulnérables à l'usurpation et à la perte.
Sécuriser les webhooks avec des signatures
Comment savoir qu'un webhook provient réellement de votre fournisseur ? Signer le payload avec un secret partagé garantit l'intégrité et l'authenticité.
Comment fonctionnent les signatures HMAC
Le fournisseur calcule un HMAC (par exemple, SHA-256) du corps de la requête à l'aide d'une clé secrète, et envoie la signature dans un en-tête (par exemple, X-Signature). Votre serveur recalcule le HMAC et le compare en utilisant une comparaison à temps constant pour éviter les attaques temporelles.
// Exemple Node.js : vérification d'une signature de webhook
const crypto = require('crypto');
function verifySignature(payload, signature, secret) {
const hmac = crypto.createHmac('sha256', secret);
hmac.update(payload);
const digest = hmac.digest('hex');
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(digest));
}
Bonnes pratiques :
- Utilisez un secret fort et unique par point de terminaison de webhook.
- Incluez un horodatage dans le payload signé pour prévenir les attaques par rejeu ; rejetez les requêtes datant de plus de quelques minutes.
- Utilisez toujours HTTPS pour protéger le payload en transit.
Implémenter des retries fiables
Même avec des signatures, des problèmes réseau ou des indisponibilités peuvent entraîner l'échec de la livraison des webhooks. Les fournisseurs réessaient généralement avec un backoff exponentiel, mais vous devez également gérer les retries de votre côté.
Idempotence : la clé de retries sûrs
Les retries peuvent entraîner un traitement en double. Utilisez des clés d'idempotence (souvent incluses dans le payload ou comme en-tête) pour garantir que chaque événement est traité exactement une fois. Stockez les ID d'événements traités et ignorez les doublons.
// Exemple : gestionnaire de webhook idempotent
const processedEvents = new Set();
app.post('/webhook', (req, res) => {
const eventId = req.body.id;
if (processedEvents.has(eventId)) {
return res.status(200).send('Already processed');
}
// traiter l'événement...
processedEvents.add(eventId);
res.status(200).send('OK');
});
Stratégie de retry côté récepteur
Si votre traitement échoue, répondez avec un statut 5xx pour déclencher le retry du fournisseur. Pour les erreurs transitoires, vous pouvez également implémenter votre propre file de retry avec backoff.
| Scénario | Réponse | Action |
|---|---|---|
| Succès | 200 OK | Pas de retry |
| Erreur de validation | 400 Bad Request | Pas de retry (corriger le payload) |
| Erreur serveur | 500 Internal Server Error | Le fournisseur réessaie |
| Limitation de débit | 429 Too Many Requests | Le fournisseur réessaie après un délai |
Surveillance et débogage des webhooks
Journalisez toutes les requêtes de webhook entrantes avec les en-têtes et les payloads (masquez les données sensibles). Utilisez un outil comme le JSON Formatter pour formater les payloads et faciliter l'inspection. Configurez des alertes pour les livraisons échouées et suivez le nombre de retries.
FAQ
Qu'est-ce qu'un payload de webhook signé ?
Un payload signé inclut une signature cryptographique (généralement HMAC) qui vérifie que la requête provient d'une source de confiance et n'a pas été altérée.
Combien de fois dois-je réessayer un webhook échoué ?
La plupart des fournisseurs réessaient 3 à 5 fois avec un backoff exponentiel. En tant que récepteur, répondez avec les codes de statut appropriés et laissez le fournisseur gérer les retries.
Puis-je utiliser des webhooks sans HTTPS ?
Non—HTTPS est essentiel pour chiffrer le payload et prévenir les attaques de type man-in-the-middle. N'acceptez jamais de webhooks sur HTTP simple.
Prêt à inspecter et déboguer les payloads de webhooks ? Essayez notre JSON Formatter gratuit pour formater et valider les données JSON instantanément.