Le WordPress d'aujourd'hui, décodé pour les développeurs

Sécurité

Une faille de logique métier permettait de s’inscrire à une régate sans payer

Un club nautique découvre qu'il est possible de valider une inscription à une régate payante sans que le paiement soit réellement vérifié côté serveur. Décryptage d'une faille de logique métier.

Par WordPress Développement • 9 janvier 2022 • 4 min de lecture • Aucun commentaire
Une faille de logique métier permettait de s'inscrire à une régate sans payer

Est-il possible de s’inscrire à un événement payant sans jamais payer ? Sur le site d’un club nautique organisant chaque année une régate ouverte aux plaisanciers extérieurs, la réponse s’est révélée oui, pendant plusieurs semaines, pour dix-sept participants qui ont ainsi pu réserver leur place sans que le paiement ne soit jamais réellement débité. La billetterie de l’événement elle-même, son interface de réservation de créneaux, ne fait pas l’objet de cet article : le problème se situait dans l’articulation entre le formulaire d’inscription et la confirmation du paiement.

Le parcours d’inscription fonctionnait ainsi : un participant remplissait un formulaire, était redirigé vers l’interface de paiement du prestataire, puis revenait sur une page de confirmation du site du club une fois le paiement effectué. Le problème tenait à cette page de retour : elle validait l’inscription dès son affichage, en se basant uniquement sur un paramètre présent dans l’URL de redirection, sans jamais vérifier auprès du prestataire de paiement que la transaction avait réellement abouti.

Le mécanisme exact de la faille

L’URL de retour, après paiement, ressemblait à /confirmation-regate/?statut=paye&inscription=482. Le code de la page, en constatant la présence de statut=paye dans l’URL, marquait directement l’inscription comme validée en base de données, sans appeler l’API du prestataire de paiement pour confirmer que la transaction correspondante existait bel et bien et avait le statut attendu. Modifier manuellement ce paramètre dans la barre d’adresse du navigateur, avant même d’avoir entré un moyen de paiement, suffisait à obtenir la même confirmation.

Pourquoi ce type de faille échappe souvent aux tests classiques

L'essentiel à retenir : Une étape validée côté client seul n'est jamais fiable ; Le statut de commande doit être confirmé par le prestataire de paiement, pas par le navigateur ; Un test manuel simple suffit à révéler ce type de faille

Un scanner de vulnérabilités automatisé, qui recherche des failles techniques comme des injections ou des failles XSS, ne détecte jamais ce genre de problème : le code ne contient aucune erreur de syntaxe, aucune injection, aucun défaut d’échappement. La faille est purement logique, elle réside dans une hypothèse implicite (« si l’utilisateur revient sur cette page avec ce paramètre, c’est qu’il a payé ») qui ne correspond à aucune vérification technique réelle.

Le correctif : vérifier le paiement côté serveur, jamais côté client

function confirmer_inscription_regate( $inscription_id, $reference_transaction ) {
    $transaction = api_prestataire_paiement_recuperer( $reference_transaction );

    if ( ! $transaction || $transaction['statut'] !== 'reussie' ) {
        return new WP_Error( 'paiement_non_confirme', 'Le paiement n\'a pas pu être vérifié.' );
    }

    if ( (float) $transaction['montant'] !== (float) get_montant_attendu( $inscription_id ) ) {
        return new WP_Error( 'montant_incorrect', 'Le montant ne correspond pas à l\'inscription.' );
    }

    update_post_meta( $inscription_id, 'statut_paiement', 'confirme' );
    return true;
}

La vérification se fait désormais systématiquement via un appel serveur à serveur vers l’API du prestataire, en fournissant la référence de transaction, et en comparant le montant réellement débité au montant attendu pour l’inscription concernée. La page de retour du navigateur ne sert plus qu’à afficher un message, elle ne déclenche plus aucune validation par elle-même.

Ajouter une confirmation par webhook, en complément

Pour se prémunir d’un cas où le visiteur fermerait son navigateur avant même d’atteindre la page de retour, un webhook envoyé directement par le prestataire de paiement, indépendant de tout comportement du navigateur, déclenche la même vérification de façon asynchrone et fiable.

Régulariser les dix-sept inscriptions concernées

Une fois la faille corrigée, le club a dû traiter individuellement les dix-sept inscriptions validées sans paiement réel, en recontactant chaque participant pour régulariser sa situation avant le jour de la régate, une démarche délicate mais nécessaire pour ne pas pénaliser ceux ayant simplement profité d’un lien partagé sans intention frauduleuse.

Un statut aussi déterminant qu’un paiement ne se lit jamais dans un paramètre d’URL contrôlé par le navigateur : il se vérifie toujours par un appel direct, serveur à serveur, vers la source qui fait foi.

En résumé

Cette faille de logique métier n’avait rien de sophistiqué techniquement : modifier un paramètre d’URL suffisait. Elle illustre un principe général qui dépasse largement ce cas précis : toute étape qui engage de l’argent réel doit être confirmée par une source faisant autorité, jamais par ce que le navigateur du visiteur affirme.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Partager :

À propos de l'auteur

WordPress Développement

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi