En bref
Un IDOR (ou BOLA côté API) survient quand une application utilise un identifiant fourni par le client pour accéder à un objet sans vérifier que l’utilisateur a le droit d’accéder à cet objet précis. Changer `/api/invoices/1042` en `/api/invoices/1043` renvoie alors la facture d’un autre client. Aucun scanner ne la détecte de façon fiable, car la réponse est techniquement correcte : seul le contexte métier dit qu’elle ne devrait pas être servie. La seule correction durable est de vérifier l’autorisation au niveau de la couche d’accès aux données, pas endpoint par endpoint.
Pourquoi cette vulnérabilité résiste
Une application affiche à l’utilisateur les seules ressources qui lui appartiennent : rien, dans l’interface, ne suggère qu’il puisse en demander d’autres. Le développeur en déduit implicitement que la requête reçue ne portera que des identifiants légitimes. Une API, elle, accepte tout ce que le client envoie.
Le défaut ne vient donc pas d’une erreur de code isolée : il repose sur une hypothèse d’architecture, « l’identifiant vient de notre interface, donc il est valide ». Elle tient jusqu’au jour où quelqu’un ouvre les outils de développement du navigateur.
C’est aussi pourquoi le défaut se multiplie. Quand la vérification d’autorisation est écrite endpoint par endpoint, il suffit qu’un endpoint sur trente l’oublie, et c’est généralement le plus récent, ajouté sous contrainte de délai.
Les formes qu’elle prend en pratique
- Identifiant séquentiel directement dans l’URL : le cas d’école, encore très répandu.
- Identifiant dans un corps JSON ou un paramètre caché, moins visible mais tout aussi exploitable.
- Identifiant d’organisation ou de locataire accepté depuis le client, alors qu’il devrait être déduit de la session.
- Accès indirect par un endpoint d’export, de rapport ou de pièce jointe, qui contourne la vérification du point d’entrée principal.
- Lecture refusée mais écriture autorisée sur le même objet, parce que la vérification n’a été ajoutée que sur la méthode GET.
- Contournement par alias ou fragment GraphQL, qui atteint le même résolveur par un autre chemin.
- Identifiant non devinable mais fuité ailleurs : un UUID n’est pas un contrôle d’accès, seulement un identifiant difficile à énumérer.
Pourquoi les outils passent à côté
Un scanner envoie une requête et analyse la réponse. Avec un IDOR : définition, la réponse est un HTTP 200 parfaitement valide, contenant des données bien formées. Rien ne distingue techniquement une facture légitime d’une facture volée : il faut savoir à qui elle appartient, et cette information n’est nulle part dans la réponse.
La détection exige donc deux identités distinctes, un objet créé par l’une, et une tentative d’accès par l’autre, puis une comparaison des réponses. C’est un raisonnement métier, qu’aucune signature ne remplace. C’est aussi la raison pour laquelle nous réclamons toujours deux comptes par rôle, dans deux organisations différentes, avant de démarrer une mission.
Corriger la classe de défaut plutôt que chaque occurrence
- 1Déplacez la vérification d’autorisation dans la couche d’accès aux données : toute requête part du contexte de l’utilisateur authentifié, jamais d’un identifiant brut reçu du client.
- 2Rendez le filtrage obligatoire par défaut. Une requête sans portée explicite doit échouer à la compilation ou aux tests, pas renvoyer toutes les lignes.
- 3Déduisez l’organisation de la session, jamais du corps de la requête. Un paramètre `tenant_id` accepté du client est un IDOR en attente.
- 4Ajoutez un test automatisé par ressource : l’utilisateur B obtient 403 ou 404 sur l’objet de l’utilisateur A. Ce test se génère, et il protège les endpoints futurs.
- 5Appliquez la même règle aux chemins secondaires : exports, pièces jointes, webhooks, rapports, résolveurs GraphQL imbriqués.
- 6Journalisez les refus d’autorisation. Une série de 403 sur des identifiants voisins est l’un des signaux de reconnaissance les plus fiables.
Que disent l’OWASP et le MITRE à ce sujet ?
L’OWASP API Security Top 10 place cette catégorie en tête de son édition 2023, sous l’intitulé API1:2023 Broken Object Level Authorization. Le texte rappelle que les API exposent souvent des identifiants d’objets, et que chaque fonction qui reçoit un tel identifiant du client doit vérifier, à chaque accès, que l’utilisateur courant a le droit d’agir sur cet objet. Il recommande aussi d’écrire des tests qui évaluent ce mécanisme et de ne pas déployer une modification qui les fait échouer.
Le catalogue de faiblesses du MITRE décrit le même défaut sous le nom CWE-639, Authorization Bypass Through User-Controlled Key : le mécanisme d’autorisation n’empêche pas un utilisateur d’accéder aux données d’un autre en modifiant la valeur de la clé qui les identifie. Trois noms (IDOR, BOLA, CWE-639), deux communautés, un seul défaut.
L’aide-mémoire de l’OWASP sur la prévention des IDOR apporte une nuance utile : des identifiants aléatoires rendent l’énumération plus difficile, mais ne remplacent jamais le contrôle d’accès. Un identifiant imprévisible qui fuit par un journal, un e-mail ou une URL partagée donne accès à l’objet tout aussi bien.
À retenir
- 1Un IDOR n’est pas un bug isolé mais une hypothèse d’architecture : l’identifiant reçu est supposé légitime.
- 2Aucun scanner ne le détecte de façon fiable : la réponse est techniquement valide, seul le métier la rend illégitime.
- 3La correction durable vit dans la couche d’accès aux données, pas dans trente vérifications endpoint par endpoint.
- 4Deux comptes dans deux organisations distinctes sont la condition minimale pour tester le cloisonnement.
Sources citées
- API1:2023 Broken Object Level Authorization, OWASP API Security Top 10
- CWE-639: Authorization Bypass Through User-Controlled Key, MITRE
- Insecure Direct Object Reference Prevention, OWASP Cheat Sheet Series
Comment tester un IDOR soi-même, sans outil spécialisé ?
Limite évidente de ce contrôle : il ne couvre que les identifiants que vous avez observés. Un identifiant caché dans un champ rarement utilisé, ou un endpoint non documenté, lui échappe.