OWASP & AppSec

Broken Access Control : explication, exemples et prévention

Broken Access Control expliqué : définition OWASP A01, IDOR, BOLA, BFLA, escalade, code vulnérable vs corrigé (Python, Node, Java), détection, prévention 2026.

Naim Aouaichia
11 min de lecture
  • Broken Access Control
  • OWASP Top 10
  • IDOR
  • BOLA
  • Autorisation
  • RBAC
  • ABAC
  • Sécurité API
  • Secure coding

Un Broken Access Control est une défaillance de l'autorisation applicative : un utilisateur accède à des ressources ou déclenche des actions qui devraient lui être refusées selon la politique de sécurité. Classée A01 du OWASP Top 10 depuis 2021 et confirmée au premier rang dans la version 2025 (100 % des applications testées présentent au moins une instance), cette catégorie regroupe les IDOR (Insecure Direct Object Reference), BOLA (Broken Object Level Authorization, OWASP API #1 en 2023), BFLA (Broken Function Level Authorization), les escalades verticales et horizontales, le force browsing, et les contournements de workflow métier. Elle se caractérise par une requête syntaxiquement valide mais sémantiquement non autorisée - ce qui la rend invisible à un WAF et très difficile à détecter par SAST. Cet article détaille les sous-types, les mécanismes d'exploitation, les exemples historiques (Optus 2022, Instagram, Facebook), les patrons de correction en Python/Node/Java, et les stratégies de prévention durables.

Définition et position OWASP

Le OWASP A01:2021 Broken Access Control couvre l'ensemble des cas où une application échoue à appliquer correctement ses règles d'autorisation. Il ne s'agit pas d'un contournement d'authentification - l'utilisateur est bien authentifié - mais d'une faille dans la vérification des droits après identification.

Chiffres clés 2021 vs 2025

MétriqueOWASP 2021OWASP 2025
Position dans le Top 10#1#1
Applications testées présentant des instances94 %100 %
Taux moyen d'incidence3,81 %en hausse
Occurrences dans le dataset318 000+ordre de grandeur supérieur
CWEs associés3430+

Source : OWASP Top 10:2021 et Top 10:2025 RC1.

CWEs principaux couverts

CWE-284   : Improper Access Control
CWE-285   : Improper Authorization
CWE-639   : Authorization Bypass Through User-Controlled Key (IDOR)
CWE-862   : Missing Authorization
CWE-863   : Incorrect Authorization
CWE-276   : Incorrect Default Permissions
CWE-732   : Incorrect Permission Assignment for Critical Resource
CWE-200   : Exposure of Sensitive Information to an Unauthorized Actor
CWE-352   : Cross-Site Request Forgery (CSRF - sous-famille)
CWE-918   : Server-Side Request Forgery (SSRF - sous-famille)

Les sous-types de Broken Access Control

La catégorie A01 regroupe des variantes aux signatures techniques distinctes.

IDOR (Insecure Direct Object Reference)

L'application expose un identifiant d'objet directement manipulable par l'utilisateur (dans l'URL, le body, les paramètres) sans vérifier que l'utilisateur demandeur est bien propriétaire ou autorisé.

Exemple classique :
  GET /api/invoice/4218
 
  Utilisateur A (id=17) accède à sa facture 4218 légitimement.
  Utilisateur B (id=42) change 4218 en 4219 et récupère
  la facture de l'utilisateur A sans vérification serveur.

BOLA (Broken Object Level Authorization)

Nom officiel d'IDOR dans le contexte API REST / GraphQL. Classé #1 du OWASP API Security Top 10 2023. Même mécanisme qu'IDOR mais formalisé pour les APIs.

BFLA (Broken Function Level Authorization)

L'attaquant accède à une fonction ou un endpoint qui aurait dû être réservé à un rôle plus élevé. Typiquement : un endpoint /api/admin/users accessible par un compte utilisateur standard.

Exemple BFLA :
  Utilisateur normal authentifié appelle :
  DELETE /api/admin/users/42
 
  Aucun middleware ne vérifie le rôle admin sur cet endpoint.
  L'utilisateur supprime des comptes.

Escalade verticale vs horizontale

Horizontale : utilisateur A accède aux ressources de l'utilisateur B
             (même rôle, ressources différentes)
             → typiquement IDOR/BOLA
 
Verticale   : utilisateur standard accède à des fonctions admin
             (rôle supérieur usurpé)
             → typiquement BFLA ou escalade de privilège

Force browsing

L'attaquant devine ou énumère des URLs non référencées publiquement mais accessibles sans contrôle : pages admin, fichiers de backup, endpoints de debug.

Exemples de paths à tester systématiquement :
  /admin/, /admin.php, /debug, /backup.zip, /.git/config
  /api/v1/internal/, /phpinfo.php, /.env, /swagger.json
  /actuator/ (Spring Boot Actuator), /wp-admin/

Mass Assignment et binding automatique

Un framework lie automatiquement les champs d'un body JSON à un objet modèle. Si l'application ne filtre pas explicitement les champs autorisés, un attaquant injecte des champs privilégiés.

POST /api/profile
{
  "name": "Alice",
  "email": "alice@example.com",
  "role": "admin",        ← injection malveillante
  "is_active": true
}
 
Si le code bind aveuglément le body à l'objet User,
l'utilisateur devient admin.

Contournement de workflow métier

L'attaquant saute des étapes dans un processus (paiement, validation, KYC) en accédant directement aux endpoints avals.

Workflow attendu :
  1. POST /cart/add
  2. POST /checkout/validate
  3. POST /payment/process
  4. POST /order/confirm
 
Contournement :
  Appel direct à POST /order/confirm
  sans passer par /payment/process si pas de vérif serveur.

Cas réels et incidents publics

Optus (Australie, septembre 2022)
  IDOR sur endpoint API client
  Exfiltration de 9,8 millions de dossiers clients
  Amende et class action estimés >150 M AUD
 
Instagram (2019)
  IDOR sur stories et posts privés
  Accès à contenus privés via manipulation d'ID
  Bug bounty : 30 000 USD
 
Facebook (2019-2020)
  Multiples IDORs sur API Graph
  Bounties cumulés >100 000 USD
 
Uber (2019)
  Prise de compte via IDOR sur reset password
  Bug bounty : 6 500 USD
 
Shopify (2020)
  IDOR permettant accès à données marchands
  Bug bounty : 25 000 USD
 
T-Mobile (2021)
  Accès non autorisé via API à 40+ millions de dossiers
  Classé A01 par les analystes post-incident

Mécanismes de défense

RBAC - Role-Based Access Control

Les utilisateurs se voient attribuer des rôles (admin, manager, user, guest) et chaque ressource ou action définit le rôle minimum requis. Simple à implémenter, limité sur des contextes fins.

# Python Flask - RBAC simple via décorateur
from functools import wraps
 
def requires_role(role):
    def decorator(f):
        @wraps(f)
        def wrapper(*args, **kwargs):
            if g.current_user is None or role not in g.current_user.roles:
                abort(403)
            return f(*args, **kwargs)
        return wrapper
    return decorator
 
@app.route("/api/admin/users")
@requires_auth
@requires_role("admin")
def list_users():
    return jsonify(User.query.all())

ABAC - Attribute-Based Access Control

Autorisation basée sur des attributs (utilisateur, ressource, action, contexte). Plus expressif que le RBAC pour les cas fins type « un manager peut voir les rapports de son équipe mais pas des autres équipes ».

ReBAC - Relationship-Based Access Control

Basé sur les relations (propriétaire, membre, collaborateur). Popularisé par Google Zanzibar (2019) et ses implémentations open source : OpenFGA (CNCF), SpiceDB, Warrant.

Authorization centralisée

Approche recommandée pour les applications non triviales : extraire la logique d'autorisation dans un service ou une librairie dédiée plutôt que de la disperser dans chaque endpoint.

Options 2026 :
  OPA (Open Policy Agent)    : standard CNCF, policies en Rego
  Cedar (AWS, 2023+)          : langage dédié, très lisible
  OpenFGA                     : ReBAC CNCF
  Casbin                      : multi-langages
  Librairie maison            : viable si scope simple

Code vulnérable vs corrigé par langage

Python / Flask

# VULNÉRABLE - IDOR sur facture
@app.route("/api/invoice/<invoice_id>")
@requires_auth
def get_invoice(invoice_id):
    return jsonify(db.get_invoice(invoice_id))
 
# CORRIGÉ - vérification de propriété
@app.route("/api/invoice/<invoice_id>")
@requires_auth
def get_invoice(invoice_id):
    invoice = db.get_invoice(invoice_id)
    if invoice is None or invoice.owner_id != g.current_user.id:
        abort(404)  # 404 plutôt que 403 pour éviter énumération
    return jsonify(invoice)

Node.js / Express

// VULNÉRABLE - Mass Assignment
app.patch('/api/profile', requireAuth, async (req, res) => {
  const user = await User.findById(req.user.id);
  Object.assign(user, req.body);  // tous les champs bindés
  await user.save();
  res.json(user);
});
 
// CORRIGÉ - whitelist explicite
app.patch('/api/profile', requireAuth, async (req, res) => {
  const ALLOWED = ['name', 'email', 'avatar_url'];
  const updates = Object.fromEntries(
    Object.entries(req.body).filter(([k]) => ALLOWED.includes(k))
  );
  const user = await User.findByIdAndUpdate(req.user.id, updates, { new: true });
  res.json(user);
});

Java / Spring Boot

// VULNÉRABLE - BFLA sans contrôle rôle
@DeleteMapping("/api/admin/users/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
    userService.delete(id);
    return ResponseEntity.noContent().build();
}
 
// CORRIGÉ - Spring Security annotation
@DeleteMapping("/api/admin/users/{id}")
@PreAuthorize("hasRole('ADMIN')")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
    userService.delete(id);
    return ResponseEntity.noContent().build();
}
 
// ENCORE MIEUX - vérification objet
@GetMapping("/api/invoice/{id}")
@PostAuthorize("returnObject.ownerId == authentication.principal.id or hasRole('ADMIN')")
public Invoice getInvoice(@PathVariable Long id) {
    return invoiceService.findById(id);
}

Détection : outils et tests

Tests automatisés par endpoint

Pour chaque endpoint protégé, créer 3 tests minimum :
 
  Test 1 : utilisateur non authentifié → 401/403
  Test 2 : utilisateur A accède à sa ressource → 200
  Test 3 : utilisateur B accède à ressource de A → 404/403
 
Pour chaque endpoint réservé à un rôle :
 
  Test 4 : utilisateur sans le rôle → 403
  Test 5 : utilisateur avec le rôle → 200

Outils de test d'autorisation 2026

OutilTypeUsage
Burp Suite + extension AutorizeProxy webTest automatisé IDOR cross-user
Burp Suite + AuthMatrixProxy webMatrice de permissions
OWASP ZAP + Access Control TestingOpen sourceTest automatisé
Semgrep règles p/owasp-top-tenSASTDétection patterns risqués
CodeQL queries communitySAST sémantiqueRequêtes dédiées A01
APIsec, Salt Security, NonameCommercial APIRuntime API authorization testing

Challenges SAST

Détecter Broken Access Control par SAST est fondamentalement limité : l'outil ne connaît pas l'intention métier de l'application. Les SAST détectent bien :

  • Les endpoints sans middleware d'authentification visible.
  • Les patterns de query DB sans filtre utilisateur.
  • Les binders automatiques de framework sans whitelist.

Ils détectent mal :

  • Les règles d'autorisation métier complexes.
  • Les workflow contournables.
  • Les escalades contextuelles (un manager d'équipe X qui accède à l'équipe Y).

D'où la nécessité combinée SAST + tests unitaires d'autorisation + pentest manuel + design review.

Prévention : les 10 règles à appliquer

  1. Refuser par défaut (deny by default) : tout endpoint sans autorisation explicite retourne 403.
  2. Centraliser l'autorisation : un service ou une librairie dédiée, pas des if dispersés.
  3. Vérifier la propriété avant tout accès : chaque requête sur un objet vérifie que object.owner_id == current_user.id ou règle équivalente.
  4. Whitelister les champs updatables : jamais de Object.assign(model, req.body) aveugle.
  5. Désactiver le listing de répertoire côté serveur web et cloud.
  6. 404 plutôt que 403 sur ressource non autorisée pour limiter l'énumération.
  7. Invalider les sessions côté serveur après logout et changement de rôle.
  8. Rate-limiter par utilisateur sur les endpoints sensibles pour ralentir l'énumération.
  9. Logger les échecs d'autorisation avec contexte (user_id, target_id, endpoint) pour détecter les tentatives.
  10. Tester l'autorisation par endpoint en tests automatisés, systématiquement.

Checklist développeur avant merge

Pour chaque PR touchant un endpoint ou une fonction sensible :

  • Cet endpoint a-t-il un middleware d'authentification ?
  • Cet endpoint vérifie-t-il le rôle ou la permission requise ?
  • Cet endpoint vérifie-t-il la propriété de l'objet accédé ?
  • Les champs modifiables sont-ils explicitement whitelistés ?
  • Les IDs exposés dans l'URL sont-ils tolérables en cas de fuite ?
  • Y a-t-il des tests unitaires d'autorisation (cas autorisé et refusé) ?
  • Les échecs d'autorisation sont-ils loggés avec contexte ?
  • La réponse d'erreur est-elle cohérente (404 vs 403) ?

Points clés à retenir

  • Broken Access Control reste #1 du OWASP Top 10 de 2021 à 2025, avec 100 % des applications testées concernées dans la version 2025.
  • Trois sous-types dominants en 2026 : IDOR (accès objet horizontal), BFLA (fonction verticale non autorisée), Mass Assignment (champs privilégiés bindés). BOLA est l'équivalent IDOR côté API REST.
  • Aucun WAF, framework ou SAST ne remplace le contrôle applicatif explicite. L'autorisation est par nature métier et doit être vérifiée côté serveur sur chaque requête.
  • Patron de correction universel : refuser par défaut, vérifier propriété avant tout accès, whitelister les champs updatables, centraliser la logique d'autorisation (OPA, Cedar, OpenFGA).
  • Test systématique à automatiser : pour chaque endpoint protégé, tester accès propriétaire (200) et accès tiers (404). Burp Autorize, AuthMatrix, OWASP ZAP Access Control Testing pour les tests larges.

Pour resituer cette vulnérabilité dans la famille OWASP complète, voir introduction au OWASP Top 10. Pour comprendre pourquoi un développeur doit investir dans la maîtrise de ces catégories, lire importance du OWASP Top 10 pour les développeurs. Pour un plan de progression complet du code review sécurisé vers l'AppSec Engineering, la roadmap AppSec Engineer 2026 détaille les 4 étapes.

Questions fréquentes

  • Quelle est la différence entre Broken Access Control, IDOR, BOLA et BFLA ?
    Broken Access Control (BAC) est la catégorie-parapluie OWASP A01 qui couvre toutes les défaillances d'autorisation. IDOR (Insecure Direct Object Reference) est une sous-famille où l'application expose un identifiant objet manipulable sans vérification de propriété. BOLA (Broken Object Level Authorization, OWASP API #1) est le nom officiel d'IDOR côté API REST. BFLA (Broken Function Level Authorization) concerne l'accès à une fonction ou un endpoint réservé, pas à un objet. Ces vulnérabilités se recoupent mais ont des signatures distinctes.
  • Pourquoi Broken Access Control est-il la vulnérabilité numéro 1 depuis 2021 ?
    Trois raisons structurelles : l'autorisation est par définition métier et ne peut pas être automatisée par un framework, elle se décline en autant de variantes que l'application a de rôles et de ressources, et sa détection automatisée par SAST est difficile car elle exige de comprendre l'intention de l'application. Les données OWASP 2025 montrent que 100 % des applications testées présentent au moins une faille de Broken Access Control, contre 94 % en 2021. Plus de 318 000 occurrences dans le dataset contributeur.
  • Comment un développeur détecte-t-il une IDOR dans son code ?
    Test systématique en deux comptes : se connecter comme utilisateur A, créer une ressource, puis se connecter comme utilisateur B et tenter d'accéder directement à la ressource de A via son identifiant. Si la réponse est 200 au lieu de 404 ou 403, c'est une IDOR. Cette vérification doit devenir un test automatisé par endpoint protégé. Les outils Burp Suite Autorize et OWASP ZAP plugin AccessControl automatisent ce test croisé sur de larges scopes.
  • Les UUID et les identifiants aléatoires protègent-ils contre les IDOR ?
    Non, ils n'offrent qu'un ralentissement par obscurité (security through obscurity). Un UUID qui fuite dans une URL partagée, un log d'application, un header Referer, un cache CDN ou une extension navigateur tierce permet à un attaquant de le capturer et de l'utiliser. La protection réelle vient de la vérification serveur systématique : chaque accès à une ressource vérifie l'identité du demandeur et ses droits, quel que soit le format de l'identifiant.
  • Que vaut un WAF contre Broken Access Control ?
    Très peu. Un WAF (Web Application Firewall) travaille sur des patterns d'attaque connus (signatures SQL injection, XSS, path traversal). Broken Access Control est par essence une requête légitime côté syntaxe, avec un simple changement d'identifiant. Le WAF ne peut pas savoir si l'utilisateur A a le droit d'accéder à la ressource de B : cette information est purement applicative. Aucun outil de périmètre ne remplace le contrôle serveur côté application.
  • Quelle différence entre authentification et autorisation ?
    L'authentification répond à 'qui es-tu ?' et valide l'identité de l'utilisateur (login, JWT, session, SSO). L'autorisation répond à 'as-tu le droit de faire ça ?' et vérifie les permissions sur une ressource ou une action. Une application peut avoir une authentification parfaite (pas de bypass, MFA, rotation des tokens) et une autorisation cassée (IDOR, escalade). Les deux sont distinctes et doivent être implémentées séparément. Broken Access Control concerne uniquement l'autorisation.

Écrit par

Naim Aouaichia

Expert cybersécurité et fondateur de Zeroday Cyber Academy

Expert cybersécurité avec un master spécialisé et un parcours hybride : développement, DevOps, DevSecOps, SOC, GRC. Fondateur de Hash24Security et Zeroday Cyber Academy. Formateur et créateur de contenu technique sur la cybersécurité appliquée, la sécurité des LLM et le DevSecOps.