Contrôle d'accès défaillant : IDOR, élévation de privilèges et contournement d'autorisation
Le contrôle d'accès est le mécanisme qui garantit qu'un utilisateur authentifié ne peut accéder qu'aux ressources et aux actions qui lui sont autorisées. C'est la catégorie numéro un du classement OWASP Top 10 depuis 2021. Contrairement à l'authentification (qui vérifie l'identité), l'autorisation vérifie les droits. Ces deux contrôles sont distincts et doivent être implémentés indépendamment.
Référence directe à un objet non sécurisée (IDOR)
Une IDOR se produit quand un identifiant prévisible (ID numérique, nom de fichier, UUID) permet d'accéder à une ressource sans vérifier que l'utilisateur en est bien le propriétaire. C'est la faille de contrôle d'accès la plus fréquente lors des audits. Elle se manifeste souvent dans les APIs REST.
Exemple d'IDOR et correction
// Vulnérable : accès à n'importe quelle facture par ID
GET /api/invoices/1337
// Serveur renvoie la facture sans vérifier à qui elle appartient :
return db.query('SELECT * FROM invoices WHERE id = ?', [req.params.id]);
// Corrigé : vérification de la propriété
return db.query(
'SELECT * FROM invoices WHERE id = ? AND user_id = ?',
[req.params.id, req.session.userId]
);
L'utilisation d'UUIDs au lieu d'IDs numériques séquentiels réduit la découverte par énumération mais ne remplace pas le contrôle d'accès. Un attaquant qui connaît un UUID (via une fuite, un partage ou une interception) peut quand même y accéder si le contrôle est absent.
Élévation de privilèges
L'élévation de privilèges permet à un utilisateur d'obtenir des droits supérieurs à ceux qui lui sont attribués. L'élévation horizontale consiste à accéder aux ressources d'un autre utilisateur de même niveau (IDOR). L'élévation verticale consiste à obtenir des droits d'un rôle supérieur (utilisateur → administrateur).
L'élévation verticale se produit généralement quand les vérifications de rôle reposent sur des données côté client (paramètre dans l'URL, champ caché dans un formulaire, valeur dans le JWT modifiable) ou quand les endpoints d'administration ne vérifient pas systématiquement le rôle de l'appelant.
Contrôle de rôle côté serveur (Express.js middleware)
function requireRole(role) {
return (req, res, next) => {
if (!req.session.user || req.session.user.role !== role) {
return res.status(403).json({ error: 'Forbidden' });
}
next();
};
}
// Appliqué sur toutes les routes admin :
app.use('/admin', requireRole('admin'));
Contournement de la logique métier
Les failles de logique métier exploitent des enchaînements d'actions non prévus par les développeurs. Exemples : modifier le prix d'un article directement dans la requête avant validation du panier, passer à l'étape de paiement sans avoir complété les étapes précédentes, réutiliser un code promo déjà utilisé en manipulant l'état de la session, appliquer une réduction prévue pour un profil spécifique en modifiant un paramètre.
Ces failles ne peuvent pas être détectées par des scanners automatiques car elles sont propres à la logique de chaque application. Elles nécessitent une revue manuelle et des tests fonctionnels de sécurité.
Mauvaise configuration CORS
CORS (Cross-Origin Resource Sharing) est le mécanisme qui permet à un script d'un domaine de faire des requêtes vers un autre domaine. Une mauvaise configuration peut permettre à un site malveillant d'appeler votre API en se faisant passer pour un utilisateur authentifié via ses cookies.
Configuration CORS dangereuse vs. sécurisée
// Dangereux : reflète l'origine de la requête sans validation
res.setHeader('Access-Control-Allow-Origin', req.headers.origin);
res.setHeader('Access-Control-Allow-Credentials', 'true');
// Sécurisé : liste blanche d'origines autorisées
const ALLOWED_ORIGINS = ['https://app.example.com', 'https://admin.example.com'];
const origin = req.headers.origin;
if (ALLOWED_ORIGINS.includes(origin)) {
res.setHeader('Access-Control-Allow-Origin', origin);
res.setHeader('Access-Control-Allow-Credentials', 'true');
}
Énumération de comptes utilisateurs
L'énumération de comptes permet à un attaquant de confirmer quels identifiants (emails, noms d'utilisateur) existent dans le système. Cela se produit quand les messages d'erreur sont différents selon que l'identifiant existe ou non : "Mot de passe incorrect" (identifiant existe) vs. "Compte introuvable" (identifiant n'existe pas). L'attaquant peut ainsi cibler uniquement les comptes confirmés pour ses attaques.
La correction : utiliser un message générique identique quelle que soit la raison de l'échec ("Identifiant ou mot de passe incorrect"), et s'assurer que le temps de réponse est constant (un hash doit être calculé même si l'identifiant n'existe pas, pour éviter les attaques temporelles).
Récapitulatif
- Vérifier la propriété à chaque accès : pour chaque ressource retournée, filtrer par l'ID de l'utilisateur courant côté serveur
- Contrôles de rôle côté serveur : jamais basés sur des données envoyées par le client
- Tester la logique métier : vérifier les enchaînements d'étapes, les prix, les quantités, les codes promo
- CORS : liste blanche explicite : ne jamais refléter l'en-tête Origin sans validation
- Messages d'erreur génériques : même message pour identifiant inconnu et mot de passe incorrect
Pour aller plus loin
Une question après la lecture ?
Vous suspectez des failles dans vos contrôles d'accès ? Envoyez un message.
Ou réservez directement un cadrage de 30 minutes
Réserver un appel →