Aller au contenu principal

Modèle de sécurité

L’intégration repose sur plusieurs mécanismes complémentaires destinés à protéger l’intégrité des requêtes, l’authenticité des webhooks, et la cohérence de l’état métier.
Le principe général est simple : toute donnée critique est vérifiée cryptographiquement côté serveur, et seul le webhook fait foi pour la validation finale du paiement.

1. Signature sortante — marchand → Lodin

Menace. Un tiers intercepte ou modifie une requête API avant qu’elle n’atteigne la passerelle, afin d’altérer un montant, un identifiant de facture ou une référence de commande.

Défense. Chaque requête est signée en HMAC-SHA256 sur une représentation canonique des champs critiques, par exemple client_id || timestamp || amount || invoice_id, à l’aide du client_secret du marchand. La signature protège l’intégrité de la requête : la modification d’un seul octet invalide la preuve cryptographique. Voir l’algorithme de signature pour la spécification exacte.

Exigences d’implémentation.

  • amount doit être exprimé en centimes entiers.
  • L’encodage doit être stable et documenté.
  • L’ordre des champs doit être strictement respecté.
  • Le timestamp doit être validé côté serveur dans une fenêtre de temps bornée.

Risque résiduel. Faible, tant que le client_secret reste confiné au serveur marchand et que la fenêtre temporelle limite les rejouements.

2. Signature entrante — Lodin → webhook marchand

Menace. Un attaquant tente d’appeler directement l’URL du webhook avec un faux événement payment.succeeded, dans le but de faire passer une commande non payée au statut payé.

Défense. Lodin signe le corps brut du webhook avec HMAC-SHA256 et transmet la signature dans l’en-tête X-Webhook-Signature. Le marchand recalcule la signature à partir du corps exact reçu et la compare à l’aide d’une comparaison à temps constant afin d’éviter les attaques par canal auxiliaire. En PHP, utilisez hash_equals; en Node.js, crypto.timingSafeEqual; en Python, hmac.compare_digest.

Exigences d’implémentation.

  • Vérifier la signature sur le corps brut, avant tout parsing modifiant.
  • Refuser toute requête non reçue via HTTPS.
  • Journaliser uniquement les métadonnées utiles, jamais le secret ni les données sensibles.
  • Rejeter les événements dont l’identifiant a déjà été traité.

Risque résiduel. Faible, limité à une compromission du secret ou à une erreur d’implémentation du validateur.

3. Jeton de retour — défense en profondeur

Menace. Un client modifie les paramètres de l’URL de retour afin d’afficher artificiellement une page de succès ou de contourner la logique métier de confirmation.

Défense. L’URL de retour embarque un jeton calculé comme HMAC_SHA256(cart_id || order_id || customer_secure_key, client_secret). Le gestionnaire de retour recalcule le jeton et rejette tout écart.

Défense en profondeur, pas mécanisme d’autorité

Même si un attaquant forgeait l’URL de retour, il ne ferait qu’influencer l’affichage de la page de confirmation. La commande ne doit jamais être marquée comme payée sur cette base. L’état métier est piloté exclusivement par le webhook, qui constitue la seule source d’autorité pour la validation du paiement.

Le jeton de retour sert à maintenir la cohérence de l’expérience utilisateur, pas à autoriser le paiement.

Risque résiduel. Faible, limité à une compromission du secret ou à une implémentation incorrecte de la validation.

4. Protection contre le rejeu

Menace. Un attaquant rejoue une requête ou un webhook valide afin de provoquer une seconde exécution d’un même événement, ou de contourner une logique métier idempotente.

Défense. Chaque message signé doit comporter :

  • un timestamp,
  • un identifiant unique de requête ou d’événement,
  • une fenêtre de validité stricte.

Le serveur doit refuser :

  • toute requête hors fenêtre temporelle,
  • tout identifiant déjà vu,
  • tout événement dont le traitement est déjà finalisé.

Pour la production, un stockage temporaire tel qu’un cache distribué avec TTL permet de bloquer efficacement les doublons.

Risque résiduel. Faible, tant que la fenêtre temporelle est appliquée et que les identifiants déjà traités sont persistés correctement.

5. Réconciliation des montants

Chaque événement de paiement réussi doit être recoupé avec le total enregistré côté commande. Le montant reçu via le webhook doit correspondre exactement au montant attendu, exprimé en unités fixes, sans dépendre de comparaisons en virgule flottante.

Règle recommandée.

  • Stocker et comparer les montants en centimes entiers.
  • Rejeter toute divergence entre le montant attendu et le montant reçu.
  • Considérer toute incohérence comme une anomalie à investiguer avant passage au statut final.

En cas d’écart, le traitement doit échouer explicitement afin de laisser le temps à une vérification manuelle ou à une reprise contrôlée.

Risque résiduel. Négligeable si les montants sont gérés en entier de bout en bout.

6. Idempotence

Les gestionnaires de webhook doivent être idempotents. Si une commande est déjà dans un état terminal, le traitement doit être court-circuité sans effet de bord.

Objectif.

  • Empêcher le double traitement.
  • Rendre les retries inoffensifs.
  • Autoriser les relances côté passerelle sans risque fonctionnel.

Bonne pratique.

  • Utiliser un identifiant d’événement unique.
  • Conserver l’état de traitement.
  • Garantir que les transitions d’état ne peuvent s’appliquer qu’une seule fois.

Risque résiduel. Très faible si la machine à états et la persistance sont correctement alignées.

7. Hygiène des secrets

Le client_secret est le matériau cryptographique central du système. Sa protection est donc critique.

Règles obligatoires.

  • Le client_secret ne doit jamais être exposé au client.
  • Le client_secret ne doit jamais être écrit dans les logs.
  • Le client_secret ne doit jamais être stocké dans le contrôle de version.
  • Le journal verbeux doit être désactivé par défaut en production.

Rotation.

  • Rotation recommandée au moins une fois par an.
  • Rotation immédiate en cas de suspicion de compromission.
  • Fenêtre de chevauchement autorisée pendant 24 heures, durant laquelle l’ancienne et la nouvelle clé sont acceptées.

Risque résiduel. Modéré en cas de fuite du secret, limité par la rotation, la surveillance et la réduction de surface d’exposition.

8. Synthèse du modèle de menaces

MenaceMitigation principaleRisque résiduel
Altération d’une requête APIHMAC sortantFaible si le client_secret reste protégé
Faux webhookHMAC entrant + comparaison à temps constantFaible si le validateur est correct
Rejeu de requête ou de webhookTimestamp + identifiant unique + idempotenceFaible, sous réserve d’une fenêtre temporelle stricte
Manipulation de l’URL de retourJeton de retour HMACFaible, car la page de retour ne valide jamais le paiement
Divergence de montantRéconciliation en centimes entiersNégligeable si les montants sont stockés en entier
Fuite de secret dans les logsJournalisation minimale et conditionnéeModéré sans discipline opérationnelle
Compromission du client_secretRotation et fenêtre de recouvrementFenêtre d’exposition entre détection et rotation

9. Ce qu’il faut retenir

Le modèle de sécurité repose sur trois idées simples :

  1. L’intégrité des messages est garantie par HMAC.
  2. L’autorité métier appartient exclusivement au webhook.
  3. La robustesse opérationnelle est assurée par l’idempotence, la réconciliation des montants et une gestion stricte des secrets.

En pratique, cela signifie qu’un attaquant peut éventuellement manipuler une interface, mais pas forcer l’état réel d’une commande sans compromettre le secret serveur.

Voir aussi