Étude de cas · Projet d'étude

Automatisation web & découverte d'un IDOR

Un projet de terminale qui m'a appris deux choses de valeur très inégale : comment piloter un navigateur par le code, et pourquoi trouver une faille et savoir quoi en faire sont deux compétences complètement différentes.

Rôle
Projet personnel, spécialité NSI
Date
2024
Stack
Python 3 · navigation programmatique · analyse HTML
Échantillon
350 entrées corrélées
Statut
Code non publié · plateforme non nommée

Le contexte

En spécialité NSI, je voulais un projet d'automatisation avec une contrainte réelle plutôt qu'un exercice. L'objectif : écrire un programme capable de parcourir une plateforme web, d'en extraire du contenu structuré, et de le mettre en correspondance avec une seconde source — le tout sans API, uniquement à partir des pages rendues.

C'est un problème classique et instructif : gestion de session, pagination, analyse de HTML non prévu pour être lu par une machine, et correspondance de textes qui ne sont jamais formulés exactement de la même façon des deux côtés.

La faille

En explorant la plateforme, j'ai constaté qu'une ressource était accessible par sa référence directe, sans que le serveur vérifie que le demandeur avait le droit d'y accéder. Il suffisait de connaître — ou de deviner — l'identifiant pour obtenir le contenu.

Cette classe de vulnérabilité porte un nom : IDOR (Insecure Direct Object Reference). Elle figure dans la catégorie « contrôle d'accès défaillant », en tête du classement OWASP. Sa cause est presque toujours la même : l'application masque un élément dans l'interface et considère qu'il est protégé, alors que l'interface n'est pas un mécanisme de sécurité. Le contrôle doit avoir lieu côté serveur, à chaque requête.

Précision nécessaire. Je ne nomme pas la plateforme, je ne publie pas le code, et je ne détaille pas la méthode d'exploitation. Une faille non corrigée reste une faille : la décrire publiquement exposerait des tiers, pas moi.

Le travail technique

L'intérêt du projet ne tient pas à la faille — un accès non contrôlé ne demande aucune compétence — mais à ce qu'il a fallu construire autour :

  • Navigation programmatique avec état. Maintenir une session entre les requêtes, suivre les redirections, et reproduire l'enchaînement qu'un utilisateur réel effectue, plutôt que d'appeler des URL isolées.
  • Analyse de HTML hostile. Le balisage n'était pas destiné à être exploité : pas d'identifiants stables, structure variable selon l'état de la page. Il a fallu ancrer l'extraction sur des repères structurels robustes plutôt que sur des classes CSS susceptibles de changer.
  • Correspondance textuelle tolérante. Les mêmes éléments s'écrivent différemment d'une source à l'autre — ponctuation, accents, espaces insécables, majuscules. Une comparaison stricte échouait sur la majorité des cas ; il a fallu normaliser les deux côtés avant de comparer.
  • Cadence maîtrisée. Le script attend entre deux requêtes. Un script qui itère aussi vite que le réseau le permet dégrade le service pour tous ses utilisateurs — c'est un déni de service accidentel.

Sur un échantillon de 350 entrées, le programme établissait la correspondance de façon fiable. C'est cette partie — la robustesse de l'extraction et de la mise en correspondance — qui représente l'essentiel du travail.

Difficultés rencontrées

Des textes identiques que rien ne rapprochait

Le premier prototype ne trouvait presque aucune correspondance, alors que les textes étaient visiblement les mêmes à l'écran. En cause : des différences invisibles — espaces insécables contre espaces ordinaires, apostrophes typographiques contre apostrophes droites, entités HTML non décodées. La leçon a dépassé le projet : deux chaînes qui s'affichent pareil ne sont pas deux chaînes égales, et toute comparaison de texte issu du web demande une normalisation explicite.

Un script trop rapide est un script qui nuit

Ma première version enchaînait les requêtes sans pause. J'ai réalisé que la charge imposée à un service qu'on ne possède pas est une nuisance réelle, même sans intention de nuire. L'ajout d'un délai entre les requêtes était une correction technique triviale ; c'est surtout la première fois que j'ai raisonné sur l'impact de mon code sur autrui plutôt que sur son efficacité.

Divulgation responsable

Voilà la partie inconfortable, et la raison pour laquelle cette fiche existe. À l'époque, je n'ai pas signalé la vulnérabilité. Je l'ai traitée comme une curiosité technique, et j'ai continué mon projet. C'est l'erreur de ce projet, et elle est plus grave que n'importe quel défaut de code : laisser une faille ouverte sans prévenir, c'est laisser exposés tous les autres utilisateurs de la plateforme.

La marche à suivre, celle que j'appliquerais aujourd'hui :

  • Arrêter immédiatement. Confirmer l'existence de la faille demande une seule requête. Tout accès supplémentaire n'apporte aucune information et aggrave la situation.
  • Ne consulter aucune donnée au-delà du strict nécessaire, et n'en conserver aucune.
  • Signaler au responsable — éditeur, établissement, ou contact sécurité — par écrit, avec la description du problème et les étapes pour le reproduire.
  • Laisser un délai de correction avant toute publication, et ne rien rendre public qui permette de reproduire l'attaque tant que le correctif n'est pas déployé.
  • Documenter, sans exposer. Ce que je fais ici : la classe de vulnérabilité et la leçon, sans la cible ni la méthode.

En France, ce cadre existe légalement : l'article L. 2321-4 du code de la défense protège la personne qui signale de bonne foi une faille à l'ANSSI. Le cadre existait déjà quand j'ai trouvé celle-ci. Je l'ignorais ; c'est précisément ce qu'un développeur qui touche à des systèmes tiers ne peut pas se permettre d'ignorer.

Ce que j'en retire

Techniquement, ce projet m'a donné des bases solides : navigation avec état, analyse de HTML fragile, normalisation de texte, respect de la charge d'un service tiers. Ce sont des compétences que j'utilise encore — la détection d'encodage des fichiers XML, dans un de mes projets en production, vient directement de là.

Mais ce que j'en retiens vraiment est ailleurs. Trouver une faille n'a aucune valeur en soi. Ce qui en a, c'est ce qu'on en fait dans l'heure qui suit. On confie un accès à un développeur parce qu'on sait comment il se comportera en trouvant quelque chose — pas parce qu'il sait trouver.

Je publie cette fiche en sachant qu'elle me met en défaut. Je la préfère à son absence : un candidat qui n'a jamais rien fait de discutable est soit inexpérimenté, soit peu sincère, et la question utile en entretien n'est pas « avez-vous déjà mal agi ? » mais « qu'en avez-vous compris ? ».