Aller au contenu principal

Vérification de la signature du webhook

La notification de paiement arrive à une adresse que seuls votre boutique et notre service connaissent. Mais l'adresse peut fuiter — des journaux, de la configuration, de l'historique de développement. Pour distinguer une notification authentique d'une contrefaçon, chaque requête est signée avec le secret du webhook.

Vérifiez la signature avant de livrer la commande ou de changer son statut.

En-têtes de signature

En-têteValeur
X-TimestampHeure d'envoi, unix time en secondes
X-SignatureLe préfixe sha256= et le HMAC-SHA256 en hexadécimal

La chaîne signée est l'heure d'envoi, un point et le corps de la requête :

1756901234.{"wallet":{...},"project":{...},"invoice":{...},"payment":{...}}

La clé de signature est le champ Secret du webhook (Webhook secret) dans les réglages du projet. Vous pouvez le réémettre au même endroit si la valeur est compromise.

Étapes de vérification

  1. Prenez le corps brut de la requête, avant d'analyser le JSON.
  2. Concaténez la valeur de X-Timestamp, un point et le corps.
  3. Calculez le HMAC-SHA256 avec le secret du webhook.
  4. Comparez le résultat avec X-Signature par une comparaison en temps constant.
  5. Rejetez la requête si X-Timestamp s'écarte trop de l'heure actuelle.

Exemples d'implémentation

<?php
$secret = 'webhook secret from your project settings';

$body = file_get_contents('php://input');
$timestamp = $_SERVER['HTTP_X_TIMESTAMP'] ?? '';
$signature = $_SERVER['HTTP_X_SIGNATURE'] ?? '';

// Guards against a replayed request
if (abs(time() - (int)$timestamp) > 300) {
http_response_code(400);
exit;
}

$expected = 'sha256='.hash_hmac('sha256', $timestamp.'.'.$body, $secret);

// hash_equals compares in constant time
if (!hash_equals($expected, $signature)) {
http_response_code(403);
exit;
}

$data = json_decode($body, true);

// Handle the order

http_response_code(200);

À garder à l'esprit

C'est le corps brut qui est signé. Si vous analysez le JSON et le reconstruisez, l'ordre des clés et les espaces changent — la signature ne correspondra pas. Calculez le HMAC avant l'analyse.

Chaque nouvelle tentative a sa propre signature. L'heure d'envoi est nouvelle à chaque tentative, donc la signature diffère aussi. Ne stockez pas une signature pour la comparer aux requêtes futures.

Le secret peut être réémis. L'ancien secret cesse de fonctionner immédiatement après la réémission, mettez donc à jour la valeur dans votre boutique au même moment.

La vérification de la signature ne remplace pas l'idempotence. La signature prouve que la requête est authentique, pas que vous la voyez pour la première fois. Une nouvelle tentative arrive avec une signature valide — vérifiez par invoice.id.