L'Insecure Direct Object Reference (IDOR) figure systématiquement parmi les vulnérabilités les plus exploitées dans les applications web et les API modernes. Malgré sa simplicité conceptuelle — le serveur fait confiance à un identifiant fourni par l'utilisateur sans vérifier la propriété de la ressource — l'impact concret est considérable : accès non autorisé à des données personnelles, financières, médicales et à des fonctions administratives. Dans le Top 10 OWASP API Security 2023, l'IDOR est classifié comme API1:2023 Broken Object Level Authorization (BOLA), le risque API le plus prioritaire. Cet article décortique chaque facette de l'IDOR dans les API REST, présente des scénarios d'attaque avec de vraies requêtes HTTP, compare le code vulnérable et sécurisé, et propose une stratégie de défense en profondeur.
1. Qu'est-ce que l'IDOR ?
Une vulnérabilité IDOR existe lorsqu'une application utilise une valeur fournie par le client — un entier, un UUID, un nom de fichier, un hash — pour récupérer ou manipuler une ressource côté serveur, sans vérifier que le principal authentifié est autorisé à accéder à cette ressource précise. Le défaut est purement une lacune d'autorisation, non d'authentification. L'utilisateur est légitimement connecté ; le serveur ne vérifie simplement pas la propriété.
L'exemple canonique : un utilisateur se connecte en tant que [email protected], accède à son profil via /api/users/101/profile et remarque le nombre 101 dans l'URL. Elle le remplace par 102. Si le serveur retourne le profil de l'utilisateur 102 au lieu d'un 403, vous avez un IDOR.
L'OWASP définit BOLA/IDOR ainsi : « L'API expose une référence directe à un objet interne (enregistrement en base, fichier, etc.) sans effectuer de contrôles d'autorisation suffisants. »
2. Pourquoi les API REST sont-elles particulièrement vulnérables ?
La conception RESTful expose intentionnellement les identifiants de ressources dans les URLs. Une API REST bien structurée ressemble à :
GET /api/users/{userId}
GET /api/orders/{orderId}
GET /api/invoices/{invoiceId}
PUT /api/documents/{docId}
DELETE /api/messages/{messageId}
Ces URLs prévisibles et orientées ressources sont un principe fondamental de REST — et elles facilitent directement les tests IDOR. Un attaquant disposant d'un seul ID valide n'a qu'à énumérer les valeurs adjacentes. Les identifiants entiers séquentiels (1000, 1001, 1002…) sont trivialement itérables. Même les systèmes basés sur UUID sont vulnérables lorsque les IDs peuvent être obtenus via d'autres réponses API.
3. Types d'IDOR
3.1 IDOR par identifiant numérique
La forme la plus évidente. Les entiers séquentiels rendent l'énumération par force brute triviale.
# Facture de la victime
GET /api/invoices/1001 HTTP/1.1
Authorization: Bearer <token_valide>
# IDOR : accès à la facture d'un autre utilisateur par décrémentation
GET /api/invoices/1000 HTTP/1.1
Authorization: Bearer <token_valide>
3.2 IDOR par UUID
Beaucoup de développeurs adoptent les UUID pensant que l'aléatoire apporte une sécurité par l'obscurité. Les UUID ne sont pas des secrets — ils apparaissent dans les liens d'e-mail, les tickets de support, les réponses d'API et l'historique du navigateur.
# UUID divulgué via GET /api/transactions
GET /api/accounts/f47ac10b-58cc-4372-a567-0e02b2c3d479/statement HTTP/1.1
Authorization: Bearer <token_victime>
3.3 IDOR par nom de fichier
Les endpoints de téléchargement de fichiers sont une localisation fréquente d'IDOR.
GET /api/files/2026/alice_tax_return.pdf HTTP/1.1
Authorization: Bearer <token_valide>
# Tentative :
GET /api/files/2026/bob_tax_return.pdf HTTP/1.1
Authorization: Bearer <token_valide>
3.4 Référence dans le corps de la requête
L'IDOR n'est pas limité aux paramètres d'URL. Les références d'objets intégrées dans les corps de requête sont tout aussi exploitables.
DELETE /api/messages HTTP/1.1
Authorization: Bearer <token_valide>
Content-Type: application/json
{"messageId": 42}
4. Requêtes HTTP de preuve de concept
La démonstration suivante illustre une escalade de privilège horizontale classique via IDOR. L'utilisateur A (id=123) est légitimement authentifié :
# Étape 1 — Requête légitime : l'utilisateur A lit son propre profil
GET /api/v1/users/123/profile HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjMiLCJyb2xlIjoidXNlciJ9.abc123
HTTP/1.1 200 OK
{"id":123,"name":"Alice","email":"[email protected]","plan":"premium"}
# Étape 2 — IDOR : l'utilisateur A lit le profil de l'utilisateur B (id=124)
GET /api/v1/users/124/profile HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjMiLCJyb2xlIjoidXNlciJ9.abc123
HTTP/1.1 200 OK <-- Devrait être 403
{"id":124,"name":"Bob","email":"[email protected]","creditCard":"****1234"}
5. IDOR dans les références indirectes et avancées
5.1 Pollution de paramètres
Certains serveurs analysent les paramètres de requête dupliqués de manière inattendue :
GET /api/cart?userId=123&userId=456 HTTP/1.1
5.2 Confusion de chemin JSON
POST /api/profile/update HTTP/1.1
Content-Type: application/json
{
"user": {
"id": 123,
"displayName": "Alice",
"admin_override_id": 1
}
}
5.3 IDOR GraphQL
query {
node(id: "VXNlcjoxMjQ=") { # décode en base64 : "User:124"
... on User {
email
creditCard { number }
}
}
}
6. Patterns IDOR réels issus du bug bounty
Les bugs IDOR dominent les paiements sur HackerOne et Bugcrowd. Les patterns les plus courants incluent :
- API de commandes et de factures : Les plateformes e-commerce exposent fréquemment des endpoints
/orders/{id}sans vérification de propriété. Les attaquants collectent les historiques d'achats, les adresses de livraison et les métadonnées des moyens de paiement. - Endpoints de dossiers médicaux : Les portails patients interrogeant
/patients/{id}/recordssans vérifier la relation du médecin ou du patient avec le dossier — une violation HIPAA aux conséquences juridiques significatives. - Endpoints de téléchargement de documents : Des plateformes SaaS servant
/documents/{docId}/downloadsans vérifier l'organisation propriétaire du document. - Systèmes de tickets de support : Plateformes utilisant des IDs de tickets prévisibles dans les URLs, permettant à des utilisateurs authentifiés d'une entreprise de lire les conversations d'une autre.
7. Code vulnérable vs. code sécurisé
Implémentation vulnérable
// VULNÉRABLE — Aucune vérification de propriété
app.get('/api/orders/:orderId', authMiddleware, async (req, res) => {
const order = await Order.findById(req.params.orderId);
if (!order) return res.status(404).json({ error: 'Commande introuvable' });
res.json(order); // retournée quel qu'en soit le propriétaire
});
Implémentation sécurisée
// SÉCURISÉ — Propriété vérifiée au niveau de la requête base de données
app.get('/api/orders/:orderId', authMiddleware, async (req, res) => {
const order = await Order.findOne({
_id: req.params.orderId,
userId: req.user.id // DOIT correspondre à l'ID de l'utilisateur authentifié
});
if (!order) return res.status(403).json({ error: 'Accès refusé' });
res.json(order);
});
Le changement essentiel réside dans la requête : findOne({ _id: ..., userId: req.user.id }). Si l'orderId n'appartient pas à l'utilisateur authentifié, la requête retourne null et l'endpoint répond par un 403.
8. Stratégie de défense en profondeur
8.1 Autorisation au niveau objet sur chaque endpoint
Chaque handler d'API qui accepte un identifiant d'objet doit effectuer une vérification de propriété avant de retourner des données ou d'exécuter des mutations. Cette vérification doit avoir lieu au niveau de la couche d'accès aux données.
8.2 Identifiants non séquentiels
Utilisez des UUID v4 (aléatoires cryptographiquement) plutôt que des entiers séquentiels. Cela élimine l'énumération triviale par incrémentation. Cependant, les UUID seuls ne constituent pas un contrôle de sécurité — les vérifications d'autorisation restent obligatoires.
8.3 Tables de références indirectes
Pour les ressources très sensibles, implémentez des tables de références indirectes : le serveur maintient un mapping limité à la session entre des tokens opaques et les vrais IDs internes.
8.4 Tests automatisés en CI/CD
Les outils pratiques incluent :
- Burp Suite avec l'extension Autorize : Enregistre les réponses d'un utilisateur privilégié, rejoue chaque requête avec le token d'un utilisateur moins privilégié et compare les réponses.
- Tests d'intégration personnalisés : Créez deux comptes utilisateurs, créez des ressources avec l'utilisateur A, et vérifiez que l'utilisateur B ne peut pas y accéder.
8.5 Journalisation et surveillance
Journalisez chaque réponse 403 avec l'ID de l'utilisateur authentifié, l'identifiant de la ressource demandée et le propriétaire réel de la ressource. Une augmentation soudaine de 403 provenant d'un seul ID utilisateur est un signal fort de sondage IDOR actif.
Conclusion
L'IDOR dans les API REST n'est pas une vulnérabilité cryptographique complexe — c'est un échec de processus où des vérifications d'autorisation qui devraient exister sont simplement absentes. Le remède est tout aussi simple : chaque opération d'accès aux données doit valider que l'identité authentifiée possède ou est autorisée à accéder à l'objet demandé. Cette vérification doit être appliquée côté serveur, ne jamais être confiée au client, et doit être présente sur chaque endpoint.
Intégrez la prévention IDOR dans votre framework API comme comportement par défaut, automatisez les requêtes à portée de propriété au niveau ORM, et testez l'autorisation indépendamment de l'authentification sur chaque endpoint de votre suite de tests.