# Webhooks expliqués simplement : signature, nouvelle tentative, sécurité

> Ce qu'est un webhook, en quoi il diffère de l'interrogation d'API et comment traiter signature, nouvelle tentative et doublons. Avec curl et Node.

Quelle: https://whovisit.app/fr/blog/webhooks-expliques-simplement-signature
Veröffentlicht: 2026-11-07
Herausgeber: Whovisit (ARAVILO, Innsbruck)

Un webhook est un appel dans l'autre sens. Au lieu que votre système demande à un service toutes les quelques minutes si quelque chose s'est passé, le service appelle une adresse chez vous dès que cela arrive. Cela économise des interrogations et livre les nouveautés plus vite. En contrepartie, vous devez mettre à disposition un récepteur et le sécuriser. Cet article explique les deux.

## Webhook ou interrogation d'API

| | Interrogation d'API (polling) | Webhook |
|---|---|---|
| Qui démarre ? | Votre système | L'expéditeur |
| Quand ? | Selon un calendrier, par exemple toutes les heures | Dès qu'un événement survient |
| Effort | Des requêtes même sans nouveauté | Un récepteur joignable est nécessaire |
| Bon pour | Rapports, rapprochement, rechargement | Notification, transmission |
| Risque | Retard jusqu'à la prochaine interrogation | Le message se perd si le récepteur ne répond pas |

En pratique, beaucoup combinent les deux : le webhook signale l'événement, l'API va chercher au besoin les détails ou comble les lacunes après une panne.

## Comment se déroule une remise

1. Un événement survient, par exemple « paiement reçu ».
2. L'expéditeur envoie un POST avec du JSON à votre adresse enregistrée (HTTPS).
3. Votre récepteur vérifie la signature, retient le message et répond vite avec un code de la plage 2xx.
4. Le travail proprement dit est ensuite effectué par votre système.

L'étape 3 est importante. Stripe recommande dans la [documentation des webhooks](https://docs.stripe.com/webhooks) de renvoyer immédiatement un code 2xx avant qu'une logique coûteuse, susceptible de provoquer un timeout, ne s'exécute. Qui comptabilise d'abord la facture et répond ensuite risque des répétitions inutiles.

## Signature : comment vérifier l'origine

Votre adresse est accessible publiquement. N'importe qui pourrait donc lui envoyer des messages inventés. C'est pourquoi les expéditeurs sérieux signent chaque message avec un secret partagé. Il est d'usage d'utiliser un HMAC avec SHA-256 sur le contenu, souvent avec un horodatage. [GitHub décrit le procédé](https://docs.github.com/en/webhooks/using-webhooks/validating-webhook-deliveries) ainsi : HMAC-SHA256 sur le contenu, représenté en hexadécimal, avec l'en-tête `X-Hub-Signature-256`. La comparaison doit se faire avec une fonction à durée constante, pour que des attaquants ne puissent rien déduire des temps de réponse.

Points importants pour votre récepteur :

- **Utiliser le contenu brut.** Calculez la signature sur les octets reçus, pas sur le JSON resérialisé. Un simple saut de ligne différent modifie la signature.
- **Vérifier l'horodatage.** Stripe utilise un horodatage dans la signature et une tolérance par défaut de cinq minutes pour empêcher les attaques par rejeu. Une tolérance de 0 désactive la vérification.
- **Garder le secret secret.** Pas dans le code, pas dans le dépôt, mais dans une variable d'environnement ou un coffre.

L'initiative [Standard Webhooks](https://www.standardwebhooks.com/) rassemble des lignes directrices open source pour expéditeurs et récepteurs. La manière dont chaque fournisseur forme concrètement sa signature figure dans sa documentation.

## Nouvelles tentatives et remise en double

Si votre récepteur ne répond pas ou avec un code d'erreur, l'expéditeur réessaie. Stripe, par exemple, répète selon sa propre documentation à intervalles croissants jusqu'à trois jours. D'autres fournisseurs ont d'autres règles, certains désactivent le webhook après trop d'échecs. Il en découle :

- **Comptez sur des doublons.** Le même événement peut arriver plusieurs fois, même si votre récepteur travaille correctement. Stripe le souligne expressément.
- **Rendez le traitement idempotent.** Cela signifie : qui traite deux fois le même message ne produit pas de second résultat. Enregistrez l'identifiant de l'événement et sautez ce qui est connu.
- **Ne comptez pas sur l'ordre.** Les événements peuvent arriver inversés. En cas de doute, vérifiez l'état actuel par l'API.

## Sécurité des deux côtés

**Pour les récepteurs :** HTTPS uniquement, vérifier la signature et l'âge, limiter la taille du message, ne pas exécuter de commandes issues du contenu. Traitez le contenu comme toute entrée venue de l'extérieur.

**Pour les expéditeurs qui appellent des adresses de clients :** qui propose des webhooks appelle des adresses saisies par d'autres. C'est une voie classique pour la Server-Side Request Forgery. L'attaquant saisit une adresse interne. Le serveur l'appelle depuis le réseau protégé. La [description de l'OWASP](https://community.owasp.org/attacks/Server_Side_Request_Forgery) cite comme cibles par exemple des services internes et des adresses de métadonnées de fournisseurs cloud. Mesures de protection judicieuses :

- n'autoriser que `https://`,
- résoudre l'adresse à la saisie et avant chaque appel et rejeter les plages privées, locales et réservées,
- ne pas suivre aveuglément les redirections,
- fixer de courtes limites de temps.

## Exemple : envoyer un message de test avec curl

Avec curl et openssl, vous pouvez tester votre récepteur sans le véritable expéditeur. Le script envoie un message signé, comme le ferait un expéditeur avec horodatage :

```bash
GEHEIMNIS="test-geheimnis"
ZEIT=$(date +%s)
INHALT='{"id":"evt_1","typ":"besuch.begonnen","firma":"beispiel-firma.example"}'
SIGNATUR="sha256=$(printf '%s.%s' "$ZEIT" "$INHALT" | openssl dgst -sha256 -hmac "$GEHEIMNIS" | sed 's/^.* //')"

curl -X POST http://localhost:3000/webhook \
  -H "Content-Type: application/json" \
  -H "X-Zeit: $ZEIT" \
  -H "X-Signatur: $SIGNATUR" \
  -d "$INHALT"
```

## Exemple : un petit récepteur en Node.js

```js
const http = require('http')
const crypto = require('crypto')
const GEHEIMNIS = process.env.WEBHOOK_GEHEIMNIS || 'test-geheimnis'
const gesehen = new Set() // en vrai : base de données

http.createServer((req, res) => {
  if (req.method !== 'POST' || req.url !== '/webhook') { res.writeHead(404); return res.end() }
  const teile = []
  req.on('data', t => teile.push(t))
  req.on('end', () => {
    const roh = Buffer.concat(teile).toString('utf8')
    const zeit = req.headers['x-zeit'] || ''
    const erwartet = 'sha256=' + crypto.createHmac('sha256', GEHEIMNIS).update(zeit + '.' + roh).digest('hex')
    const erhalten = String(req.headers['x-signatur'] || '')
    const a = Buffer.from(erwartet), b = Buffer.from(erhalten)
    const echt = a.length === b.length && crypto.timingSafeEqual(a, b)
    const frisch = Math.abs(Date.now() / 1000 - Number(zeit)) < 300
    if (!echt || !frisch) { res.writeHead(401); return res.end() }
    const ereignis = JSON.parse(roh)
    if (!gesehen.has(ereignis.id)) { gesehen.add(ereignis.id); console.log('neu:', ereignis.typ) }
    res.writeHead(200); res.end('ok')
  })
}).listen(3000)
```

Le récepteur vérifie la signature et l'âge, saute les identifiants connus et répond immédiatement. Pour l'exploitation, il vous faut en plus HTTPS, une limite de taille et une file d'attente pour le traitement ultérieur.

## Où les webhooks sont répandus

Les services de paiement, les plateformes de code et les outils de formulaire signalent des événements par webhook. La reconnaissance des visiteurs le peut aussi : si le système signale une entreprise qui visite votre site, elle atterrit directement dans un outil de votre choix. La manière dont cela mène à un système de vente est montrée dans [Faire entrer les visites du site web dans le CRM](https://whovisit.app/blog/website-besuche-ins-crm). L'alternative par interrogation est décrite dans [Quelles entreprises visitent mon site web ?](https://whovisit.app/blog/welche-firmen-besuchen-meine-website). Quelles données circulent alors, [Comment fonctionne la reconnaissance d'entreprises ?](https://whovisit.app/blog/firmenerkennung-website-technik) l'explique.

## Questions fréquentes

**Quelle est la différence entre webhook et API ?** Avec l'API, votre système demande, avec le webhook l'expéditeur se manifeste de lui-même. Les deux peuvent se combiner.

**Que se passe-t-il si mon récepteur tombe en panne ?** La plupart des expéditeurs répètent la remise pendant un certain temps. La durée et la fréquence figurent dans la documentation du fournisseur. Pour les lacunes, prévoyez un rapprochement par l'API.

**Suffit-il de vérifier l'adresse de l'expéditeur ?** Non. Les adresses d'expéditeur peuvent être usurpées et changent. Seule la signature avec un secret que vous seul et l'expéditeur connaissez est fiable.
