Signature des Webhooks
Secret HMAC
Comment fonctionne HMAC
HMAC implique l'utilisation d'une fonction de hachage cryptographique (dans ce cas, SHA-256) et d'une clé secrète pour produire une signature unique pour la charge utile. Cette signature est ensuite envoyée avec la requête. Le récepteur peut utiliser la même clé secrète pour générer une signature pour la charge utile reçue et la comparer avec la signature fournie. Si les deux signatures correspondent, la charge utile est considérée comme authentique.
Où trouver le secret
Pour récupérer le secret, allez dans la page développeur dans la section webhook. Ici, vous trouverez la clé secrète pour vérifier les signatures. Si nécessaire, vous pouvez également faire pivoter le secret pour assurer une sécurité continue.
Faire pivoter le secret invalidera l'ancienne clé et générera une nouvelle, qui devra ensuite être mise à jour dans votre application pour maintenir le bon fonctionnement du webhook.

Exemples d'implémentation
- NodeJS
- PHP
- Python
Génération de la signature
const crypto = require('crypto');
const generateSignature = (secret, payload) => {
return crypto.createHmac('sha256', secret).update(payload).digest('hex');
};
Vérification de la signature
const verifySignature = (secret, payload, receivedSignature) => {
const expectedSignature = generateSignature(secret, payload);
try {
return crypto.timingSafeEqual(Buffer.from(expectedSignature), Buffer.from(receivedSignature));
} catch (e) {
return false;
}
};
Gestion de la requête Webhook
const express = require('express');
const app = express();
app.use(express.json());
app.post('/webhook', function(req, res) {
const secret = process.env.SECRET;
const signature = req.headers['x-signature'];
if (signature == null) {
res.status(403).send({ message: 'Signature non trouvée' });
} else if (verifySignature(secret, JSON.stringify(req.body), signature)) {
res.status(200).send({ message: 'La signature du webhook est valide' });
} else {
res.status(403).send({ message: 'La signature du webhook est invalide' });
}
});
app.listen(3000, () => {
console.log('Le serveur tourne sur le port 3000');
});
Génération de la signature
function generateSignature($secret, $payload) {
return hash_hmac('sha256', $payload, $secret);
}
Vérification de la signature
function verifySignature($secret, $payload, $receivedSignature) {
$expectedSignature = generateSignature($secret, $payload);
return hash_equals($expectedSignature, $receivedSignature);
}
Gestion de la requête Webhook
<?php
$secret = getenv('SECRET');
$headers = getallheaders();
$signature = isset($headers['x-signature']) ? $headers['x-signature'] : null;
$payload = file_get_contents('php://input');
if ($signature === null) {
http_response_code(403);
echo json_encode(['message' => 'Signature non trouvée']);
exit;
}
if (verifySignature($secret, $payload, $signature)) {
http_response_code(200);
echo json_encode(['message' => 'La signature du webhook est valide']);
} else {
http_response_code(403);
echo json_encode(['message' => 'La signature du webhook est invalide']);
}
?>
Génération de la signature
import hmac
import hashlib
def generate_signature(secret, payload):
return hmac.new(secret.encode(), payload.encode(), hashlib.sha256).hexdigest()
Vérification de la signature
def verify_signature(secret, payload, received_signature):
expected_signature = generate_signature(secret, payload)
return hmac.compare_digest(expected_signature, received_signature)
Gestion de la requête Webhook
from flask import Flask, request, jsonify
import os
app = Flask(__name__)
@app.route('/webhook', methods=['POST'])
def webhook():
secret = os.getenv('SECRET')
signature = request.headers.get('x-signature')
payload = request.get_data(as_text=True)
if signature is None:
return jsonify({'message': 'Signature non trouvée'}), 403
if verify_signature(secret, payload, signature):
return jsonify({'message': 'La signature du webhook est valide'}), 200
else:
return jsonify({'message': 'La signature du webhook est invalide'}), 403
if __name__ == '__main__':
app.run(port=5000)