Webhooks expliqués : charges utiles signées et tentatives

Backend2026-10-26TryQuickToolBox

Pourquoi les webhooks ont besoin de charges utiles signées et de tentatives

Vous venez d'intégrer un service tiers qui envoie des webhooks à votre point de terminaison. Tout fonctionne en test, mais en production, vous remarquez des événements manquants, des livraisons en double et, pire encore, quelqu'un usurpe des requêtes vers votre URL de webhook. Sans mesures de sécurité et de fiabilité appropriées, les webhooks peuvent devenir une source de bugs et de vulnérabilités.

Les webhooks sont des callbacks HTTP qui notifient votre application lorsqu'un événement se produit. Ils sont simples en concept mais délicats en pratique car ils franchissent les frontières de confiance et les problèmes de fiabilité du réseau. Dans ce guide, nous couvrirons deux aspects critiques : les charges utiles signées pour vérifier l'authenticité et les tentatives pour assurer la livraison. Nous allons parcourir des implémentations pratiques que vous pouvez appliquer immédiatement.

Comprendre les charges utiles signées

Une charge utile signée est un moyen pour l'expéditeur de prouver que le webhook provient de lui et n'a pas été altéré. L'expéditeur calcule une signature cryptographique sur le corps de la requête (et parfois les en-têtes) en utilisant un secret partagé, puis inclut cette signature dans un en-tête. Votre point de terminaison recalcule la signature et la compare.

L'algorithme le plus courant est HMAC-SHA256. Il est rapide, sécurisé et largement pris en charge. Voici comment cela fonctionne :

  1. L'expéditeur et le récepteur partagent une clé secrète (configurée dans les paramètres du webhook).
  2. Pour chaque webhook, l'expéditeur crée une signature en hachant la charge utile avec le secret à l'aide de HMAC-SHA256.
  3. La signature est envoyée dans un en-tête comme X-Signature.
  4. Le récepteur calcule le même HMAC et le compare en utilisant une comparaison à temps constant pour éviter les attaques temporelles.

Implémentation de la vérification HMAC en Node.js

Voyons un exemple concret. Supposons que l'expéditeur inclut la signature dans X-Signature sous forme de chaîne hexadécimale. Voici comment vous la vérifiez dans une route Express :

const crypto = require('crypto');
const express = require('express');
const app = express();

// Utiliser le corps brut pour la vérification de la signature
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');
  }

  // Traiter l'événement
  const event = JSON.parse(req.body);
  console.log('Received event:', event.type);

  res.status(200).send('OK');
});

app.listen(3000);

Important : Utilisez toujours le corps brut de la requête pour le calcul de la signature, pas le JSON analysé. L'analyse et la re-stringification peuvent modifier les espaces et l'ordre, cassant la signature.

Horodatage et protection contre la relecture

Les signatures seules ne préviennent pas les attaques par relecture. Un attaquant pourrait capturer une requête signée valide et la renvoyer plus tard. Pour atténuer cela, incluez un horodatage dans la charge utile signée ou dans un en-tête. Par exemple, ajoutez un en-tête X-Timestamp avec l'heure Unix. Le récepteur vérifie que l'horodatage est dans une fenêtre de tolérance (par exemple, 5 minutes) et rejette les requêtes plus anciennes.

Incluez également l'horodatage dans le calcul de la signature pour empêcher toute altération. L'expéditeur calcule le HMAC sur timestamp + '.' + body. Le récepteur fait de même et compare.

Implémentation des tentatives pour une livraison fiable

Les webhooks voyagent sur l'internet public, donc les échecs sont inévitables : délais réseau, erreurs serveur (5xx) ou votre point de terminaison temporairement indisponible. Un système de webhook robuste doit réessayer les livraisons échouées.

Stratégies de tentative

Les stratégies de tentative courantes incluent :

Une politique typique pourrait être : réessayer jusqu'à 5 fois avec un retrait exponentiel et du jitter, en commençant à 10 secondes. Après cela, marquer la livraison comme échouée et éventuellement alerter.

Idempotence : Gestion des doublons

Les tentatives peuvent entraîner des livraisons en double. Votre point de terminaison doit être idempotent—traiter le même événement deux fois ne doit pas causer d'effets secondaires comme facturer deux fois un client. Incluez un ID d'événement unique dans la charge utile (par exemple, event.id) et stockez les ID traités pendant une période raisonnable. Avant de traiter, vérifiez si l'ID a déjà été vu.

Alternativement, concevez vos opérations pour être naturellement idempotentes (par exemple, en utilisant des upserts au lieu d'insertions).

Répondre rapidement

Votre point de terminaison de webhook doit accuser réception rapidement (dans les quelques secondes) et traiter l'événement de manière asynchrone. Si le traitement prend trop de temps, l'expéditeur peut expirer et réessayer, provoquant des doublons. Utilisez une file d'attente : répondez avec 200 OK immédiatement après avoir vérifié la signature, puis mettez l'événement en file d'attente pour un traitement en arrière-plan.

Comparaison des mesures de sécurité des webhooks

Mesure Objectif Complexité de mise en œuvre
Signature HMAC Vérifier l'authenticité et l'intégrité Faible
Validation de l'horodatage Prévenir les attaques par relecture Faible
Clés d'idempotence Éviter le traitement en double Moyenne
Liste blanche d'IP Restreindre aux IP d'expéditeurs connus Faible (mais fragile)
HTTPS Chiffrer les données en transit Faible

Bien que la liste blanche d'IP puisse ajouter une couche, elle n'est pas fiable car les IP des expéditeurs peuvent changer. Fiez-vous principalement aux signatures.

Tester votre point de terminaison de webhook

Utilisez des outils comme ngrok pour exposer votre serveur local et déclencher des webhooks de test depuis le tableau de bord du fournisseur. Vérifiez que les signatures sont correctement validées et que les tentatives fonctionnent en simulant des échecs (par exemple, renvoyer 500 pour les premières tentatives).

Lors du débogage, vous pourriez avoir besoin d'inspecter les charges utiles JSON. Le JSON Formatter peut vous aider à imprimer joliment et valider rapidement les charges utiles de webhook.

FAQ

Qu'est-ce qu'une charge utile de webhook signée ?

Une charge utile signée inclut une signature cryptographique (généralement HMAC) qui permet au récepteur de vérifier que la requête provient de l'expéditeur attendu et n'a pas été altérée. Elle est calculée à l'aide d'un secret partagé.

Combien de fois dois-je réessayer un webhook échoué ?

Il n'y a pas de nombre universel, mais 3 à 5 tentatives avec un retrait exponentiel sont courantes. Après cela, enregistrez l'échec et envisagez d'alerter. L'objectif est de gérer les problèmes transitoires sans tentatives infinies.

Puis-je utiliser JWT pour les signatures de webhook ?

Oui, certains fournisseurs utilisent JWT (JSON Web Tokens) pour signer les webhooks. Le jeton contient des revendications et est signé avec un secret ou une clé privée. La vérification est similaire : validez la signature et vérifiez les revendications comme l'expiration.

Prêt à implémenter des webhooks sécurisés ? Commencez par générer un secret fort, ajouter la vérification HMAC et configurer des tentatives avec idempotence. Pour une inspection rapide des charges utiles pendant le développement, essayez notre JSON Formatter pour formater et valider le JSON des webhooks.