Webhooks expliqués : charges utiles signées et stratégies de réessai
Vous venez de créer un point de terminaison webhook pour recevoir des événements d'un service tiers. Tout fonctionne en test, mais en production, vous remarquez que certains événements n'arrivent jamais ou, pire, que vous recevez des événements en double provoquant des incohérences de données. Ce sont des pièges classiques des webhooks qui découlent de deux aspects critiques : l'authenticité de la charge utile et la fiabilité de la livraison.
Les webhooks sont des callbacks HTTP déclenchés par des événements, qui poussent des données vers votre application en temps réel. Contrairement au polling, ils sont efficaces et quasi instantanés. Mais ils introduisent des défis : comment savoir que la requête provient bien de l'expéditeur attendu, et comment gérer les échecs lorsque le récepteur est temporairement indisponible ? Cet article explore les charges utiles signées et les mécanismes de réessai, en vous donnant des modèles pratiques pour construire des intégrations webhook résilientes.
Pourquoi les webhooks ont besoin de signatures
Les points de terminaison webhook sont des URL accessibles publiquement. Sans vérification, n'importe qui peut envoyer des requêtes falsifiées à votre point de terminaison, déclenchant potentiellement des actions non autorisées ou une corruption des données. Les charges utiles signées résolvent ce problème en ajoutant une signature cryptographique à chaque requête, vous permettant de vérifier l'identité de l'expéditeur et de vous assurer que la charge utile n'a pas été altérée.
La plupart des fournisseurs utilisent HMAC (Hash-based Message Authentication Code) avec un secret partagé. L'expéditeur calcule un hachage de la charge utile à l'aide du secret et l'inclut dans un en-tête. Vous recalculez le hachage de votre côté et comparez. S'ils correspondent, la requête est légitime.
Implémentation de la vérification HMAC
Passons en revue une implémentation typique en Node.js. Supposons que le fournisseur envoie une signature dans l'en-tête X-Signature, calculée comme HMAC-SHA256 du corps brut de la requête à l'aide de votre secret.
const crypto = require('crypto');
const express = require('express');
const app = express();
// Utiliser un parseur de corps brut pour préserver la charge utile exacte
app.use(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');
}
// Traiter l'événement
const event = JSON.parse(req.body);
// ... traiter l'événement
res.status(200).send('OK');
});
Points clés :
- Utilisez toujours le corps brut de la requête pour la vérification, pas le JSON analysé. L'analyse peut modifier les espaces ou l'ordre des clés, cassant le hachage.
- Utilisez une comparaison à temps constant pour éviter les attaques temporelles.
- Gardez votre secret en sécurité ; faites-le tourner périodiquement et prenez en charge plusieurs secrets actifs pendant la rotation.
Concevoir une stratégie de réessai
Même avec des signatures, les livraisons peuvent échouer en raison de problèmes réseau, d'indisponibilité du serveur ou de délais d'attente. Une stratégie de réessai robuste garantit une livraison éventuelle sans surcharger votre système ni l'expéditeur.
1. Accusez réception rapidement, traitez de manière asynchrone
Votre point de terminaison webhook doit répondre avec un statut 2xx dès que possible, idéalement en quelques secondes. Si le traitement prend plus de temps, mettez l'événement en file d'attente pour un traitement en arrière-plan. Cela évite les délais d'attente et permet à l'expéditeur de considérer la livraison comme réussie.
2. Mettez en œuvre un backoff exponentiel avec jitter
Lorsqu'une livraison échoue (réponse non-2xx ou délai d'attente), l'expéditeur doit réessayer avec des délais croissants. Le backoff exponentiel (par exemple, 1s, 2s, 4s, 8s...) empêche de marteler votre point de terminaison. L'ajout d'un jitter aléatoire évite les problèmes de troupeau tonitruant lorsque de nombreux webhooks échouent simultanément.
Exemple de calendrier de réessai :
- Tentative 1 : immédiate
- Tentative 2 : après 30 secondes
- Tentative 3 : après 2 minutes
- Tentative 4 : après 10 minutes
- Tentative 5 : après 1 heure
Après un nombre maximum de réessais (par exemple, 5), l'expéditeur doit arrêter et vous notifier (par exemple, par e-mail ou tableau de bord).
3. Gérez les doublons avec l'idempotence
Les réessais peuvent provoquer des livraisons en double. Votre point de terminaison doit être idempotent : traiter le même événement plusieurs fois doit avoir le même effet que le traiter une fois. Utilisez un ID d'événement unique à partir de la charge utile et stockez-le. Avant le traitement, vérifiez si l'ID a déjà été vu ; si c'est le cas, renvoyez 200 sans retraiter.
Approches courantes :
- Contrainte d'unicité de la base de données sur l'ID d'événement.
- Ensemble Redis avec TTL pour les ID récemment traités.
- Clés d'idempotence dans votre logique métier.
Comparaison : charges utiles signées vs autres mesures de sécurité
| Méthode | Avantages | Inconvénients |
|---|---|---|
| Signature HMAC | Vérifie l'authenticité et l'intégrité ; sans état | Nécessite la gestion d'un secret partagé |
| Liste blanche d'IP | Simple à mettre en œuvre | Les IP peuvent changer ; ne convient pas aux environnements dynamiques |
| Authentification basique | Facile à ajouter | Les identifiants sont envoyés à chaque requête ; moins sécurisé |
| JWT dans l'en-tête | Peut inclure des revendications et une expiration | Surcoût d'émission/validation du jeton |
Les signatures HMAC sont la norme de facto car elles sont sans état, efficaces et offrent une sécurité forte lorsqu'elles sont correctement mises en œuvre.
Bonnes pratiques pour les consommateurs de webhooks
- Validez les signatures à chaque requête, même en développement.
- Répondez rapidement ; déchargez le traitement lourd vers une file d'attente.
- Journalisez tout—en-têtes, charge utile et résultat du traitement—pour le débogage.
- Surveillez les échecs et configurez des alertes pour les erreurs répétées.
- Utilisez HTTPS pour protéger les charges utiles en transit.
- Faites tourner les secrets régulièrement et prenez en charge plusieurs secrets actifs pendant la rotation.
Bonnes pratiques pour les producteurs de webhooks
- Signez les charges utiles avec un secret unique pour chaque consommateur.
- Incluez un ID d'événement unique pour faciliter l'idempotence.
- Réessayez avec backoff et limitez les tentatives.
- Fournissez un tableau de bord pour que les consommateurs puissent consulter les journaux de livraison et rejouer les événements.
- Documentez clairement votre schéma de signature.
Tester votre implémentation de webhook
Utilisez des outils comme ngrok pour exposer votre serveur local et simuler des livraisons de webhooks. Écrivez des tests unitaires pour la vérification des signatures et la logique d'idempotence. Pour les tests de charge, envisagez des outils capables d'envoyer des requêtes signées à grande échelle.
Lors du débogage, inspectez la charge utile brute et les en-têtes. Un formateur JSON peut aider à visualiser la structure de la charge utile. Essayez notre JSON Formatter pour imprimer et valider rapidement les charges utiles de webhook.
FAQ
Qu'est-ce qu'une charge utile webhook signée ?
Une charge utile signée inclut une signature cryptographique (généralement HMAC) qui permet au récepteur de vérifier l'identité de l'expéditeur et de s'assurer que la charge utile n'a pas été altérée. Elle est calculée à l'aide d'un secret partagé et du corps de la requête.
Combien de fois un webhook doit-il être réessayé ?
Il n'y a pas de nombre universel, mais la pratique courante est de 3 à 5 réessais avec un backoff exponentiel. Au-delà, l'événement est considéré comme échoué et le consommateur doit être notifié pour enquêter ou rejouer manuellement.
Puis-je utiliser JWT au lieu de HMAC pour les signatures de webhook ?
Oui, JWT peut fonctionner, mais cela ajoute de la complexité (émission de jeton, expiration). HMAC est plus simple et suffisant pour la plupart des cas d'utilisation. Choisissez en fonction de votre infrastructure existante et de vos besoins.
Prêt à inspecter et déboguer les charges utiles de webhook ? Utilisez notre JSON Formatter gratuit pour formater et valider le JSON instantanément.