Le champ qui l'emporte : deux champs, un même nom, une seule réponse

Fondamentaux de la Sécurité Niveau 3/4 ~4 min 2 octobre 2026

Le défi

Le conseil de Brackwell verse à ses bénévoles une indemnité à l'heure. Les paiements d'un bénévole ne correspondent plus à sa feuille de temps imprimée depuis quatre mois : la feuille signée par le superviseur indique un nombre, le traitement de paie un autre, et le portail affiche le nombre signé sur tous les écrans que l'on consulte. Personne n'a trouvé de moyen de modifier une feuille déjà soumise. Voici la page telle que le navigateur la détenait au moment de l'envoi du formulaire. Lisez ce que le formulaire enverrait réellement et donnez le nombre d'heures que le serveur a accepté.

Ce que tu vas apprendre

  • Repérer les noms de paramètres dupliqués dans le code source d'un formulaire
  • Expliquer comment différents frameworks résolvent un paramètre HTTP répété
  • Distinguer la valeur qu'une page affiche de la valeur qu'elle envoie
  • Reconnaître un champ de reporting qui lit des données différentes de celles soumises
  • Expliquer pourquoi une interface cohérente avec elle-même peut quand même être fausse

Compétences testées

Analyse du code source côté clientAnalyse des paramètres HTTPRaisonnement sur la logique métier

Prérequis

  • Ce qu'est un formulaire HTML et un champ caché (hidden input)

Comment ça marche

HTTP n'impose pas qu'un paramètre n'apparaisse qu'une fois. Un formulaire avec deux champs partageant le même nom envoie les deux, et la requête est parfaitement bien formée. Ce que l'application voit dépend entièrement de la façon dont son framework résout la répétition, et les frameworks ne s'accordent pas : PHP et Rails conservent le dernier, Express avec son analyseur par défaut produit un tableau, Flask renvoie le premier via un accès par crochets et la liste complète via getlist, et certains équilibreurs de charge et pare-feux applicatifs web l'analysent encore différemment de l'application derrière eux.

Ce désaccord est la classe de faille en jeu ici. Il compte surtout quand une occurrence est visible et sous le contrôle de l'utilisateur tandis que l'autre est cachée et porte une valeur qui représente de l'argent, une permission ou une identité. Le correctif auquel on pense d'instinct, cacher le champ, ne change rien : un champ caché n'est ni secret ni en lecture seule, il n'est simplement pas affiché.

La seconde moitié de ce cas vaut autant que la première. Les rapports lisent hours_display, un champ différent avec une valeur différente, si bien que toutes les surfaces visibles par un humain se sont accordées entre elles pendant quatre mois. Quand deux chemins de code lisent deux champs censés contenir la même chose, ils finissent par diverger, et celui que personne ne regarde est celui qui décide.

Erreurs fréquentes

  • Répondre 12. C'est le contrôle visible et le chiffre signé, ce qui explique justement pourquoi l'écart est resté inexpliqué pendant quatre mois.
  • Supposer que le dernier champ l'emporte. Vrai pour PHP et Rails. Le commentaire cite Werkzeug, où l'accès par crochets renvoie le premier.
  • Répondre 418. total_hours_ytd est un cumul, ce n'est pas le champ envoyé pour cette semaine.
  • Ne lire que l'aperçu. Trois des champs qui comptent ne sont jamais affichés.

Comment s'en protéger

Rejetez l'ambiguïté au lieu de la résoudre.

  • Traitez un paramètre répété comme une requête malformée. Lisez avec getlist, et si la liste contient plus d'une entrée, renvoyez un 400 et journalisez-le.
  • N'envoyez jamais une valeur que le serveur peut calculer. Les heures payées doivent provenir uniquement du champ soumis, validé côté serveur par rapport à l'enregistrement d'approbation du superviseur.
  • N'ayez qu'un seul champ de référence. Les rapports, les exports et le traitement de la paie doivent tous lire la même valeur stockée, pour que tout désaccord soit impossible plutôt qu'invisible.
  • Recoupez les sorties. Un rapport hebdomadaire comparant les heures payées aux heures approuvées aurait détecté cela dès le premier cycle de paie.

Solution complète

Les membres Pro et Max débloquent la solution complète étape par étape.

Passer Pro

Statistiques de la communauté

166 résolutions
88% taux de réussite
M2F14M3 Premier sang

Hacks du jour associés

34 000+ Hackers Vrais labs Gratuit
Commencer Gratuitement ou résolvez le hack du jour, sans compte