IDOR (CWE-639, OWASP A01:2021) : substituer un identifiant d'objet pour accéder aux données de n'importe quel utilisateur — première cause de violations de données SaaS.
TL;DR
WHERE owner_id = session.user_id — et PostgreSQL RLS en filet de sécuritéUne référence directe à un objet non sécurisée (IDOR) survient quand une application utilise une entrée contrôlée par l'utilisateur — paramètre d'URL, champ de corps de requête, en-tête HTTP — pour accéder à un objet interne sans vérifier l'autorisation du demandeur sur cet objet spécifique. Le serveur confirme que l'utilisateur est authentifié mais omet la deuxième question : cet utilisateur possède-t-il cet enregistrement ? Classifiée CWE-639 (Authorization Bypass Through User-Controlled Key), l'IDOR est la sous-catégorie la plus répandue d'OWASP A01:2021 Contrôle d'accès défaillant.
L'IDOR diffère du contournement d'authentification (qui annule la vérification d'identité entièrement), de l'injection SQL (qui manipule la structure de requête) et du CSRF (qui forge des requêtes via le navigateur de la victime). La faille est purement dans la couche d'autorisation : credentials valides, permission invalide. BOLA (Broken Object Level Authorization, OWASP API1:2023) désigne la même faille dans les API REST et GraphQL — l'authentification au niveau endpoint passe, mais l'objet retourné appartient à un autre utilisateur. BFLA (API5:2023) est la variante verticale : la vérification manquante concerne le rôle de l'appelant plutôt que la propriété de la ressource.
L'OWASP Top 10:2025 place le contrôle d'accès défaillant en première position — conservée depuis 2021. L'ensemble de données contributif recense 1 839 701 occurrences, 32 654 CVE mappées, et un chiffre frappant : 100 % des applications testées présentent une forme de contrôle d'accès défaillant. Les données bug bounty confirment — environ 49 % de tous les findings de haute et critique sévérité sur HackerOne sont liés à l'IDOR ou au contrôle d'accès, avec plus de 200 rapports IDOR valides soumis mensuellement.
Un endpoint applicatif accepte un identifiant d'objet fourni par l'utilisateur. Le serveur récupère l'objet via cet identifiant sans vérifier la propriété dans la jointure. L'utilisateur A fournit l'identifiant de l'utilisateur B ; le serveur retourne les données de B.
L'attaque se déroule en quatre étapes :
Un IDOR horizontal confirmé via entier séquentiel :
GET /api/utilisateurs/1338/profil HTTP/1.1
Host: cible.exemple.com
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...<token_utilisateur_1337>
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": 1338,
"email": "victime@corp.com",
"telephone": "+33-6-55-01-92-00",
"adresse": "12 rue de la Paix, 75001 Paris"
}L'identifiant apparaît dans quatre emplacements : chemin d'URL (/api/utilisateurs/1338/), chaîne de requête (?user_id=1338), corps de requête ({"user_id": 1338}), et en-têtes (X-User-ID: 1338). Les quatre emplacements doivent être testés.
| Variante | Technique | Impact | Page dédiée |
|---|---|---|---|
| Référence directe à un objet | Énumération d'entier séquentiel dans URL/requête/corps | Exfiltration de PII, données de compte | /learn/idor-direct |
| Escalade horizontale de privilèges | Accès latéral entre pairs (même rôle, utilisateur différent) | Vol de données inter-utilisateurs | /learn/idor-horizontal |
| Escalade verticale de privilèges (BFLA) | Utilisateur standard appelant endpoints admin ou méthodes HTTP élevées | Prise de contrôle admin, destruction de données | /learn/idor-vertical |
| Référence indirecte à un objet | Référence opaque (nom de fichier, slug, hash) mais réversible | Divulgation de fichiers, énumération de comptes | /learn/idor-indirect |
| Mass Assignment | Injection de champs privilégiés dans le corps POST/PUT | Escalade de rôle, manipulation de solde | /learn/idor-mass-assignment |
La référence directe à un objet est la forme de base : GET /api/commandes/84921 avec order_id=84922 récupère la commande de l'utilisateur suivant. Les entiers séquentiels — valeur par défaut dans PostgreSQL auto-increment et MySQL AUTO_INCREMENT — rendent cela trivial. La violation Optus a répété ce schéma 9,8 millions de fois.
L'escalade horizontale de privilèges (accès latéral entre pairs) représente la majorité des rapports bug bounty IDOR de haute sévérité. La méthodologie à deux comptes est la référence : s'authentifier comme utilisateur A, créer une ressource comme utilisateur B, puis tenter de la lire/modifier/supprimer en tant qu'utilisateur A.
L'escalade verticale de privilèges (BFLA) cible des fonctions plutôt que des données. Trois vecteurs distincts existent : (1) accès direct aux endpoints admin (GET /api/admin/utilisateurs avec un token utilisateur standard) ; (2) contournement par override de méthode HTTP via X-HTTP-Method-Override: DELETE sur les frameworks qui l'honorent (Rails, Django REST Framework, Spring) ; (3) rétrogradation de version API — GET /api/v2/admin/utilisateurs retourne 403 mais GET /api/v1/admin/utilisateurs retourne 200 parce que l'endpoint legacy manque le middleware d'autorisation ajouté en v2.
Les références indirectes à un objet semblent sécurisées mais ne le sont pas. Une référence de facture FAC-2024-04521 s'énumère en FAC-2024-04522. Un identifiant encodé en Base64 eyJ1c2VyX2lkIjoxMzM3fQ== se décode en {"user_id":1337} — ré-encoder avec 1338. Un identifiant utilisateur haché en MD5 est réversible via des tables arc-en-ciel. L'IDOR de second ordre (stocké) est temporellement séparé : l'utilisateur A fournit l'identifiant d'un autre utilisateur lors de l'inscription ; une requête de tableau de bord ultérieure récupère les données via cet identifiant stocké sans re-vérifier la propriété.
Le mass assignment injecte des champs privilégiés (role, is_admin, tenant_id, balance) dans les corps de requête POST/PUT que les frameworks lient directement aux objets ORM. CVE-2024-7297 (Langflow, CVSS 8,8) : PATCH /api/v1/users/<USER_ID> avec corps {"is_superuser": true} accordait un accès super-admin complet à tout utilisateur authentifié.
L'OWASP API Security Top 10:2023 sépare l'IDOR en deux entrées distinctes :
| Terme | Entrée OWASP API | CWE | Périmètre |
|---|---|---|---|
| BOLA — Broken Object Level Authorization | API1:2023 | CWE-639 | Propriété d'objet — retourne les données d'un autre utilisateur |
| BFLA — Broken Function Level Authorization | API5:2023 | CWE-285 | Niveau de privilège — l'appelant invoque des fonctions non autorisées |
BOLA diffère de l'IDOR web classique dans son implication pour les outils : les vérifications d'authentification au niveau endpoint (validation de la présence d'un Bearer token) ne détectent pas BOLA. La faille d'autorisation est au niveau du resolver — une route qui vérifie correctement l'identité mais n'impose pas la propriété sur l'objet retourné. En GraphQL, BOLA se manifeste quand une requête node(id: "VXNlcjoxMzM4") retourne les données de l'Utilisateur 1338 à la session de l'Utilisateur 1337, parce que le resolver d'ID global manque de validation de propriété par appelant.
BFLA ne concerne pas la propriété des données mais l'autorisation de fonction. Un utilisateur standard appelant DELETE /api/admin/utilisateurs/5 alors que seuls les admins peuvent supprimer des utilisateurs est du BFLA. Le test automatisé le plus efficace : sonder tous les endpoints correspondant à /admin|manage|settings|internal|backoffice|system|config|moderation|staff|superuser/ avec une session à faible privilège et vérifier les réponses 200 contenant du contenu admin substantiel.
L'IDOR inter-tenant est la variante la plus impactante dans le SaaS. Un seul tenant_id manquant dans une clause WHERE expose les données d'une organisation entière plutôt que celles d'un seul utilisateur. Les scores CVSS atteignent systématiquement 8,8–9,5. Le multiplicateur de blast radius est le nombre d'enregistrements que le tenant détient.
Dans les architectures multi-tenant, quatre schémas d'échec se répètent : (1) couches de cache partagées (Redis, Memcached) indexées par ID d'objet sans préfixe tenant ; (2) processeurs de tâches en arrière-plan acceptant object_id depuis une file sans validation tenant_id ; (3) index de recherche retournant des résultats sur tous les tenants parce que le filtre tenant au niveau requête a été omis ; (4) endpoints API acceptant tenant_id comme paramètre contrôlé par l'utilisateur. Le schéma obligatoire : dériver le contexte tenant exclusivement de la session authentifiée, jamais des paramètres de requête. Chaque requête ORM doit inclure WHERE tenant_id = :session_tenant_id comme contrainte structurelle.
L'IDOR GraphQL exploite le schéma d'ID global de la spécification Relay. Un ID utilisateur est encodé comme base64("User:1337") = VXNlcjoxMzM3. Décoder le sien, incrémenter l'entier final, ré-encoder : VXNlcjoxMzM4 accède à l'Utilisateur 1338. La requête :
query {
node(id: "VXNlcjoxMzM4") {
... on User { email donneesPrivees }
}
}Rapport HackerOne #2122671 (plateforme HackerOne, prime 12 500 $) : une mutation GraphQL acceptait un ID d'objet dans ses arguments sans le valider contre l'identité de l'appelant. Tout utilisateur authentifié pouvait supprimer les certifications et licences de n'importe quel autre utilisateur.
Les requêtes batch amplifient le blast radius : une seule requête GraphQL contenant 1 000 requêtes node(id: ...) aliasées récupère les données de 1 000 utilisateurs différents tout en générant un seul événement d'authentification.
Les systèmes basés sur JWT sont vulnérables quand l'application fait confiance à un claim user_id intégré dans le token sans re-valider la propriété contre la base de données. Trois vecteurs d'attaque : (1) secret HS256 faible ou devinable permettant de forger un token avec un user_id arbitraire ; (2) rétrogradation alg: none (si le serveur l'accepte) supprimant la vérification de signature ; (3) injection kid substituant la clé de validation. Le schéma — décoder le JWT, modifier user_id de 1337 à 1338, forger une nouvelle signature ou exploiter un contournement de signature — convertit un compte en lecture seule en accès à n'importe quel autre compte.
Les connexions WebSocket maintiennent un état persistant ; l'IDOR survient quand un client s'abonne à un canal de ressource (subscribe {order_id: 12345}) sans que le serveur vérifie la propriété. Les connexions persistantes permettent une énumération rapide et peu bruyante. Les outils DAST standard ne rejouent pas les trames WebSocket — les tests manuels ou des outils personnalisés sont requis.
L'UUID v1 est dérivé d'un horodatage et d'une adresse MAC. Un attaquant qui obtient n'importe quel UUID de l'application (depuis une réponse API, une notification, ou un lien partagé) peut estimer les UUID voisins dans une fenêtre temporelle — l'attaque sandwich. CVE-2024-45719 (Apache Answer) : les tokens de réinitialisation de mot de passe générés avec UUID v1 pouvaient être forcés par tout attaquant connaissant l'horodatage de création du compte, permettant la prise de contrôle de compte sans authentification.
L'UUID v4 utilise 122 bits d'entropie cryptographique. L'énumération est irréalisable. Cependant, l'UUID v4 ne prévient pas l'IDOR quand l'attaquant obtient une référence légitimement — depuis un lien de document partagé, une réponse API qui fuite des ID pairs, ou des logs serveur accessibles. L'autorisation doit toujours être imposée côté serveur quel que soit le schéma d'identifiant.
CVE-2025-27507 — IDOR API Admin ZITADEL (CVSS 9,0 Critique, 2025)
ZITADEL, une plateforme d'identité Go/gRPC, utilisait des permissions IAM au niveau organisation plutôt qu'au niveau système sur 12 endpoints HTTP de l'API Admin. Des utilisateurs non-admin authentifiés appelaient /idps/ldap et /idps/ldap/{id} pour modifier la configuration LDAP de l'instance, redirigeant l'authentification vers un serveur malveillant. Impact : prise de contrôle complète de compte pour tous les utilisateurs LDAP de l'instance. CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N.
CVE-2024-46528 — IDOR KubeSphere (CVSS 6,5 Élevé, 2024)
KubeSphere v3.4.1 et v4.1.1 accordaient des permissions excessives au GlobalRole authenticated (CWE-639). Des utilisateurs authentifiés à faible privilège accédaient aux données de surveillance au niveau cluster et aux listes d'utilisateurs complètes sans élévation — données réservées au rôle cluster-admin. CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N. Corrigé dans KubeSphere 4.1.3.
CVE-2024-45719 — Token UUID v1 prévisible Apache Answer (2024) Apache Answer générait des tokens de réinitialisation de mot de passe en UUID v1 (horodatage + MAC). Des attaquants obtenant un UUID quelconque de l'application calculaient des tokens valides pour d'autres comptes dans une fenêtre temporelle — attaque sandwich. Impact : prise de contrôle de compte sans credentials.
CVE-2024-7297 — Mass Assignment Langflow (CVSS 8,8 Élevé, 2024)
Langflow avant v1.0.13 : PATCH /api/v1/users/<USER_ID> acceptait {"is_superuser": true} de tout utilisateur authentifié. Accès super-admin complet accordé — tous les flux, credentials et infrastructure. Corrigé en v1.0.13 par ajout de filtrage des champs côté serveur.
CVE-2026-29056 — Mass Assignment Kanboard via chemin d'invitation (Élevé, 2026)
Kanboard ≤ 1.2.50 : UserInviteController::register() passait tous les paramètres POST directement à UserModel::create() sans filtrer le champ role. Tout destinataire d'invitation email s'inscrivait avec role=app-admin dans le corps du formulaire, obtenant un accès administrateur complet. La chaîne RCE suivait via l'installation de plugin. Corrigé par unset($values['role']) avant la création du modèle.
Violation McHire de McDonald's (juillet 2025, 64 millions d'enregistrements)
Les chercheurs Ian Carroll et Sam Curry ont trouvé un IDOR à entier séquentiel sur l'endpoint interne McHire /api/lead/cem-xhr : le paramètre lead_id retournait l'enregistrement de chat complet de n'importe quel candidat sans vérification d'authentification. Données exposées : noms, emails, numéros de téléphone, historiques de chat, résultats de tests de personnalité et tokens de session pour l'usurpation de candidats. Il s'agit de la plus grande violation IDOR connue à ce jour.
Violation de données Optus (septembre 2022, 9,8 millions d'enregistrements)
Un endpoint REST public — /api/customers/{id} — utilisait des entiers séquentiels sans authentification. Le endpoint avait été corrigé sur le domaine principal mais le correctif n'a pas été appliqué à un domaine secondaire. L'attaque : GET /api/customers/1 jusqu'à GET /api/customers/9800000, répété 9,8 millions de fois. Résultat réglementaire : amende de 1,36 million AUD de l'ACMA.
Rapport HackerOne #2122671 — IDOR GraphQL plateforme HackerOne (12 500 $, 2024) Une mutation GraphQL acceptait des ID d'objet sans les valider contre l'identité de l'appelant. Tout utilisateur authentifié pouvait supprimer les certifications et licences de n'importe quel autre utilisateur. Prime : 12 500 $.
Rapport HackerOne #415081 — IDOR PayPal Business Management (10 500 $)
IDOR sur /businessmanage/users/api/v1/users permettant d'ajouter des utilisateurs secondaires à n'importe quel compte business par manipulation de paramètre. Prime : 10 500 $.
Les tests IDOR nécessitent au minimum deux identités authentifiées. Les tests mono-utilisateur ne peuvent pas détecter les défaillances d'autorisation.
X-User-ID, X-Account-ID, en-têtes personnalisés)La détection confirme un IDOR lorsqu'un contournement d'autorisation est corroboré par des signaux indépendants : un statut passant de 403 à 200, le corps de réponse renvoyant l'identifiant de la cible mais pas celui de l'attaquant, des PII distinctes apparaissant dans une réponse JSON de structure par ailleurs identique, ou plusieurs champs JSON non-timestamp divergeant entre deux sessions.
Burp Suite Autorize (Barak Tawily) : moteur de rejeu à deux sessions testant chaque requête interceptée contre une session secondaire. Meilleur outil DAST pour l'IDOR par consensus des praticiens.
AuthMatrix : définit une matrice N-rôles × M-endpoints et teste toutes les combinaisons. Optimal pour les applications avec des structures de permissions multi-rôles complexes.
Semgrep AI IDOR detection (bêta 2025) : trace les flux request.params[id] → db.find(id=id) et vérifie la présence de filtres de propriété. Atteint 22 % de vrais positifs sur les flux mono-fichier ; échoue complètement quand l'autorisation s'étend à des middleware ou des classes parentes.
BreachVex détecte l'IDOR via une analyse différentielle multi-sessions : chaque endpoint est testé avec des sessions primaire et secondaire authentifiées, la propriété est extraite sémantiquement des réponses JSON (id, user_id, email, account_id), et les findings sont corroborés par plusieurs signaux complémentaires (contournement de statut, echo d'ID, comparaison de PII, divergence de champs JSON, delta de taille de réponse) avant qu'un finding ne soit remonté. L'accès inter-sessions en écriture escalade en BFLA de sévérité CRITIQUE.
La règle la plus importante : dériver l'identité utilisateur de la session authentifiée et inclure la contrainte de propriété dans chaque requête de base de données comme exigence structurelle — pas une vérification optionnelle.
# VULNÉRABLE — authentifie mais n'autorise pas
@router.get("/api/factures/{facture_id}")
async def obtenir_facture(facture_id: int, user: User = Depends(get_current_user)):
facture = await db.get(Facture, facture_id) # récupère N'IMPORTE QUELLE facture
return facture
# SÉCURISÉ — propriété imposée au niveau requête
@router.get("/api/factures/{facture_id}")
async def obtenir_facture(facture_id: int, user: User = Depends(get_current_user)):
facture = await db.execute(
select(Facture)
.where(Facture.id == facture_id)
.where(Facture.owner_id == user.id) # verrou de propriété — structurel
)
if not facture:
raise HTTPException(status_code=404) # 404 pas 403 — évite l'oracle d'existence
return factureRetourner 404, pas 403, sur un accès non autorisé. Retourner 403 confirme l'existence de la ressource et facilite l'énumération.
RLS impose l'autorisation au niveau du moteur de base de données — le filet de sécurité le plus robuste disponible. Même si le code applicatif oublie la clause WHERE, la base de données rejette la requête. RLS ne peut pas être contourné par des bugs applicatifs.
-- Activer RLS sur la table
ALTER TABLE factures ENABLE ROW LEVEL SECURITY;
-- Créer une politique : chaque utilisateur ne voit que ses propres lignes
CREATE POLICY factures_isolation_proprietaire ON factures
USING (owner_id = current_setting('app.current_user_id')::int);
-- Définir l'ID utilisateur courant dans votre connexion (exemple FastAPI) :
-- await db.execute("SET app.current_user_id = :uid", {"uid": user.id})
-- Chaque requête suivante sur cette connexion est automatiquement scoppée.// Middleware d'autorisation réutilisable — à attacher avant tout handler touchant des ressources propriétaires
const verifierPropriete = (Modele, paramId = 'id') => async (req, res, next) => {
const ressource = await Modele.findByPk(req.params[paramId]);
if (!ressource) return res.status(404).json({ erreur: 'Non trouvé' });
if (ressource.userId !== req.user.id) {
return res.status(404).json({ erreur: 'Non trouvé' });
}
req.ressource = ressource;
next();
};
// Appliqué avant le handler — impossible d'atteindre le handler sans passer la vérification de propriété
router.get('/api/documents/:id',
authentifier,
verifierPropriete(Document),
(req, res) => res.json(req.ressource)
);# VULNÉRABLE — référence opaque mais aucun filtre de propriété
def telecharger_facture(request):
ref = request.GET.get("ref")
facture = Facture.objects.get(ref=ref) # facture de n'importe quel utilisateur
return FileResponse(open(facture.chemin_pdf, "rb"))
# SÉCURISÉ — propriété imposée sur l'identifiant indirect aussi
def telecharger_facture(request):
ref = request.GET.get("ref")
# get_object_or_404 retourne 404 pas 403 — prévient l'oracle de ressource
facture = get_object_or_404(Facture, ref=ref, owner=request.user)
return FileResponse(open(facture.chemin_pdf, "rb"))from pydantic import BaseModel
from typing import Optional
# N'exposer que les champs contrôlables par l'utilisateur
class DemandeMAJUtilisateur(BaseModel):
nom_affiche: str
bio: Optional[str] = None
# is_admin, role, tenant_id : NON déclarés — rejetés quel que soit ce qu'envoie le client
@router.patch("/utilisateurs/moi")
async def maj_utilisateur(user: User = Depends(get_current_user),
data: DemandeMAJUtilisateur = ...):
# Le schéma Pydantic agit comme liste d'autorisation — champs supplémentaires lèvent 422 avant l'exécution
await db.utilisateurs.update(id=user.id, **data.model_dump(exclude_unset=True))L'UUID v4 réduit le risque d'énumération mais ne remplace pas l'autorisation. Une fois partagé (lien de collaboration, réponse API, log serveur), un attaquant avec cette référence peut la tester entre sessions. L'autorisation doit toujours être imposée côté serveur quel que soit le type d'identifiant.
Utiliser UUID v4 pour les identifiants exposés externalement. Ne jamais exposer directement des entiers auto-incrémentés aux consommateurs API. Ne jamais utiliser UUID v1 pour des tokens sensibles en sécurité (réinitialisation de mot de passe, liens d'invitation) — sa dérivation temporelle le rend forçable.
Pour les structures de permissions complexes, trois modèles s'appliquent :
Intégrer des assertions inter-utilisateurs dans la suite de tests :
# Exemple pytest — exécuté à chaque PR
def test_idor_facture(client_a, client_b, facture_b):
"""L'utilisateur A ne doit pas récupérer la facture de l'utilisateur B."""
reponse = client_a.get(f"/api/factures/{facture_b.id}")
assert reponse.status_code in (403, 404), (
f"IDOR détecté : utilisateur_a a récupéré la facture appartenant à utilisateur_b "
f"(statut={reponse.status_code})"
)Ce schéma intercepte les régressions d'autorisation avant le déploiement en production.
Qu'est-ce qu'une référence directe à un objet non sécurisée (IDOR) ? Une vulnérabilité IDOR survient quand une application utilise une entrée contrôlée par l'utilisateur pour accéder à un objet interne — enregistrement de base de données, fichier, ressource API — sans vérifier l'autorisation du demandeur sur cet objet spécifique. Classifiée CWE-639, elle relève d'OWASP A01:2021 Contrôle d'accès défaillant.
Quelle est la différence entre IDOR et BOLA ? L'IDOR est le terme général pour le web. BOLA (Broken Object Level Authorization, OWASP API1:2023) est l'équivalent API-spécifique. BFLA (API5:2023) est la variante verticale où la vérification manquante porte sur le niveau de privilège et non la propriété. Les trois décrivent le même gap d'autorisation dans des contextes différents.
L'IDOR est-il toujours dans l'OWASP Top 10 en 2025 ? Oui. Le contrôle d'accès défaillant (A01:2025) conserve sa position #1. L'OWASP recense 1 839 701 occurrences et note que 100 % des applications testées contiennent une forme de contrôle d'accès défaillant.
L'IDOR peut-il mener à une prise de contrôle de compte ? Oui. La chaîne courante : IDOR sur un endpoint de réinitialisation de mot de passe → modification de l'email de la victime → réinitialisation vers la boîte de l'attaquant → prise de contrôle complète. CVE-2025-27507 (ZITADEL, CVSS 9,0) démontre un IDOR permettant la prise de contrôle au niveau instance pour tous les utilisateurs LDAP.
Les UUID suffisent-ils à prévenir l'IDOR ? Non. UUID v4 empêche l'énumération ; il ne prévient pas l'accès une fois une référence obtenue. UUID v1 est partiellement prévisible via des attaques sandwich (CVE-2024-45719). Les vérifications d'autorisation sont obligatoires quel que soit le type d'identifiant.
Comment tester l'IDOR ? Créer deux comptes. Enregistrer les ressources du compte B. Depuis le compte A, tenter l'accès avec les identifiants de B sur toutes les méthodes HTTP et emplacements de paramètre. Utiliser l'extension Autorize de Burp Suite pour automatiser le rejeu à deux sessions.
Comment prévenir l'IDOR ?
Dériver l'identité uniquement de la session. Inclure WHERE owner_id = session_user_id dans chaque requête. Retourner 404 (pas 403) sur les accès non autorisés. Utiliser UUID v4 pour les IDs exposés. Activer PostgreSQL RLS comme filet de sécurité côté base de données. Écrire des assertions inter-utilisateurs en CI/CD.
Comment Row-Level Security prévient-il l'IDOR ? RLS impose la contrainte de propriété au niveau du moteur de base de données. Même si le code applicatif omet la clause WHERE, la base de données rejette la requête en fonction de la politique active. Les bugs applicatifs ne peuvent pas contourner RLS.
Une vulnérabilité IDOR survient quand une application utilise une entrée contrôlée par l'utilisateur — paramètre d'URL, champ de corps de requête, en-tête HTTP — pour accéder à un objet interne (enregistrement de base de données, fichier, ressource API) sans vérifier que le demandeur est autorisé à accéder à cet objet spécifique. Classifiée CWE-639, elle relève d'OWASP A01:2021 (Contrôle d'accès défaillant).
L'IDOR est le terme général pour les applications web. BOLA (Broken Object Level Authorization) est son équivalent API, position API1:2023 du classement OWASP API Security Top 10. BFLA (Broken Function Level Authorization, API5:2023) est la variante verticale où la vérification manquante porte sur le niveau de privilège et non sur la propriété de l'objet.
Oui. Le contrôle d'accès défaillant — la catégorie parente — est OWASP A01:2025, conservant sa première place depuis 2021. L'OWASP recense 1 839 701 occurrences, 32 654 CVE associées, et indique que 100 % des applications testées présentent une forme de contrôle d'accès défaillant.
Oui. La chaîne la plus courante : IDOR sur un endpoint de réinitialisation de mot de passe → modification de l'email de la victime → déclenchement de la réinitialisation vers la boîte de l'attaquant → prise de contrôle totale du compte. CVE-2025-27507 (ZITADEL, CVSS 9.0) démontre un IDOR permettant la prise de contrôle au niveau instance pour tous les utilisateurs LDAP.
Non. L'UUID v4 (aléatoire) empêche l'énumération mais ne protège pas contre un accès une fois la référence obtenue légitimement. L'UUID v1 est partiellement prévisible par attaque sandwich temporelle (CVE-2024-45719 Apache Answer). L'autorisation côté serveur reste obligatoire quel que soit le schéma d'identifiant.
UUID v1 est dérivé d'un horodatage et d'une adresse MAC. Un attaquant connaissant l'heure approximative de création d'un compte peut calculer ou forcer les UUID voisins. UUID v4 est cryptographiquement aléatoire (122 bits d'entropie) et ne peut pas être énuméré. Aucun des deux ne remplace les vérifications d'autorisation côté serveur.
Créer deux comptes A et B. Enregistrer les ressources appartenant à B. Depuis la session de A, tenter d'accéder à chaque identifiant de B dans les chemins d'URL, paramètres de requête, corps de requête et en-têtes. Tester toutes les méthodes HTTP (GET, PUT, PATCH, DELETE). L'extension Autorize de Burp Suite automatise ce rejeu à deux sessions.
1) Dériver l'identité utilisateur exclusivement de la session authentifiée. 2) Inclure la contrainte de propriété dans chaque requête SQL (WHERE owner_id = session_user_id). 3) Retourner 404 (pas 403) sur les accès non autorisés. 4) Utiliser UUID v4 pour les identifiants exposés. 5) Activer PostgreSQL Row-Level Security comme filet de sécurité côté base de données. 6) Écrire des assertions inter-utilisateurs dans le pipeline CI/CD.
PostgreSQL RLS impose la contrainte de propriété au niveau du moteur de base de données. Une politique USING (owner_id = current_setting('app.user_id')::int) empêche structurellement le retour des lignes d'un autre utilisateur, même si le code applicatif omet la clause WHERE. RLS ne peut pas être contourné par des bugs applicatifs.
L'escalade horizontale de privilèges survient quand un utilisateur accède aux ressources d'un autre utilisateur au même niveau de privilège. L'utilisateur A lit ou modifie les commandes, messages ou profil de l'utilisateur B. Il s'agit de la variante IDOR la plus répandue, représentant la majorité des rapports bug bounty de haute sévérité.
L'escalade verticale de privilèges (BFLA) survient quand un utilisateur standard invoque des endpoints ou méthodes HTTP réservés aux administrateurs. L'attaquant accède aux tableaux de bord d'administration ou aux API de gestion des utilisateurs sans le rôle requis. CVE-2025-27507 en est un exemple réel.
Dans les architectures multi-tenant, un IDOR qui franchit les limites de tenant expose les données d'une organisation entière plutôt que celles d'un seul utilisateur — le rayon de blast est multiplié par des milliers. Les scores CVSS atteignent systématiquement 8,8–9,5 pour les IDOR inter-tenant.
Partiellement. Les outils DAST ne détectent l'IDOR qu'avec deux sessions authentifiées distinctes. Les outils SAST (Semgrep AI, 2025) atteignent 22 % de vrais positifs sur les flux mono-fichier mais échouent quand l'autorisation s'étend à plusieurs fichiers ou middleware. Le test manuel à deux comptes reste la référence.
Le coût moyen de remédiation d'un IDOR est d'environ 25 000 $ (prime + ingénierie). La violation Optus (IDOR, 2022) a entraîné une amende de 1,36 million AUD. L'IDOR McHire de McDonald's (juillet 2025, 64 millions d'enregistrements) est la plus grande violation IDOR connue. Les primes bug bounty vont de 3 000 $ (typique) à 12 500 $ (rapport HackerOne #2122671).
Un IDOR horizontal typique (PII en lecture seule) score CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N = 6,5 Élevé. Un IDOR en écriture score 8,1 Élevé. CVE-2025-27507 (ZITADEL IDOR → prise de contrôle complète) score 9,0 Critique.