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

Backend2026-11-08TryQuickToolBox

Vous venez d'intégrer le webhook d'un fournisseur de paiement. La documentation indique « nous ferons un POST vers votre endpoint lorsqu'un paiement réussit ». Simple, non ? Puis vous remarquez des événements en double, des notifications manquées et une alerte de sécurité concernant des requêtes falsifiées. Les webhooks sont simples en concept mais délicats en production. Cet article explique comment implémenter correctement les webhooks en utilisant des charges utiles signées et des tentatives, afin de construire des intégrations fiables et sécurisées.

Que sont les webhooks ?

Un webhook est une API inversée : au lieu que votre application interroge un service pour obtenir des mises à jour, le service pousse des événements vers votre endpoint via HTTP POST. C'est efficace et quasi temps réel. Les utilisations courantes incluent les notifications de paiement, les déclencheurs CI/CD et les intégrations de chat.

Mais les webhooks introduisent des défis : comment savoir que la requête provient réellement du fournisseur ? Et si votre serveur est hors service ? Et si le même événement arrive deux fois ? Abordons-les un par un.

Sécuriser les webhooks avec des charges utiles signées

N'importe qui peut envoyer une requête HTTP à votre endpoint. Sans vérification, des attaquants pourraient falsifier des événements, entraînant fraude ou corruption de données. La solution standard consiste à signer la charge utile avec un secret partagé.

Comment fonctionnent les signatures HMAC

Le fournisseur et vous partagez une clé secrète. Pour chaque événement, le fournisseur calcule un HMAC (Hash-based Message Authentication Code) du corps de la requête en utilisant ce secret et envoie la signature dans un en-tête (par exemple, X-Signature). Vous recalculez le HMAC de votre côté et comparez. S'ils correspondent, la requête est authentique et non altérée.

Voici un exemple minimal en Python avec Flask :

import hmac
import hashlib
from flask import Flask, request, abort

app = Flask(__name__)
SECRET = b'your_shared_secret'

@app.route('/webhook', methods=['POST'])
def webhook():
    signature = request.headers.get('X-Signature')
    if not signature:
        abort(400, 'Missing signature')
    body = request.get_data()
    expected = hmac.new(SECRET, body, hashlib.sha256).hexdigest()
    if not hmac.compare_digest(expected, signature):
        abort(401, 'Invalid signature')
    # Process the event
    return '', 200

Utilisez toujours hmac.compare_digest pour une comparaison à temps constant afin de prévenir les attaques temporelles. Vérifiez également la signature avant d'analyser le corps JSON pour éviter un traitement inutile.

Bonnes pratiques pour les signatures

Gérer les échecs avec des tentatives

Les webhooks sont de type fire-and-forget du point de vue du fournisseur, mais votre endpoint peut être temporairement indisponible. Pour garantir la livraison, les fournisseurs mettent en œuvre des politiques de tentatives. En tant que récepteur, vous devez être préparé aux tentatives et aux doublons.

Stratégies de tentatives utilisées par les fournisseurs

La plupart des fournisseurs réessaient avec un backoff exponentiel : par exemple, immédiatement, puis après 1 minute, 5 minutes, 30 minutes, etc., jusqu'à un nombre maximal de tentatives (souvent 5 à 10). Certains vous permettent également de configurer un calendrier de tentatives. Le comportement exact varie, alors lisez la documentation du fournisseur.

Concevoir votre endpoint pour les tentatives

Votre endpoint doit :

Exemple de vérification d'idempotence en Python :

processed_events = set()  # In production, use a database or cache

@app.route('/webhook', methods=['POST'])
def webhook():
    # ... signature verification ...
    event = request.json
    event_id = event['id']
    if event_id in processed_events:
        return '', 200  # Already processed
    # Process event
    processed_events.add(event_id)
    return '', 200

Tester votre implémentation de webhook

Avant de passer en production, testez minutieusement votre endpoint :

  1. Simulez des requêtes signées : écrivez des tests unitaires qui génèrent des signatures valides et invalides.
  2. Testez les scénarios de tentatives : simulez des échecs et assurez-vous que votre endpoint gère les doublons.
  3. Utilisez les outils du fournisseur : de nombreux fournisseurs offrent une CLI ou un tableau de bord pour envoyer des événements de test.
  4. Surveillez et journalisez : journalisez les événements entrants (sans données sensibles) et configurez des alertes pour les échecs de signature ou les taux d'erreur élevés.

Comparaison : Polling vs Webhooks

AspectPollingWebhooks
LatenceDépend de l'intervalle (par exemple, minutes)Quasi temps réel
Charge serveurÉlevée (requêtes fréquentes)Faible (uniquement sur événements)
ComplexitéSimple à implémenterNécessite vérification de signature et gestion des tentatives
FiabilitéVous contrôlez les tentativesLe fournisseur contrôle les tentatives ; vous devez gérer les doublons

FAQ

Comment vérifier une signature de webhook ?

Calculez le HMAC du corps brut de la requête en utilisant le secret partagé et comparez-le à l'en-tête de signature à l'aide d'une fonction de comparaison à temps constant. Vérifiez toujours avant de traiter la charge utile.

Que doit retourner mon endpoint pour accuser réception d'un webhook ?

Retournez un code de statut 2xx (par exemple, 200 OK) dès que vous avez reçu et mis en file d'attente l'événement pour traitement. Évitez un traitement long dans le gestionnaire de requêtes pour prévenir les timeouts.

Comment gérer les livraisons de webhooks en double ?

Utilisez une clé d'idempotence provenant de la charge utile de l'événement (ou un ID d'événement unique) pour suivre les événements traités. Stockez ces ID dans une base de données ou un cache et ignorez le traitement si l'ID a déjà été vu.

Prêt à tester vos charges utiles de webhook ? Utilisez notre JSON Formatter pour embellir et valider le corps JSON des webhooks entrants, facilitant ainsi le débogage.