Bugs d’autorisation dans les apps CRUD : auditer rôles, locataires et routes
Apprenez à repérer et corriger les bugs d’autorisation dans les apps CRUD en auditant les vérifications de rôle, le scoping des locataires et les routes API avant que des utilisateurs n’accèdent aux données d’autrui.

Pourquoi les utilisateurs finissent par voir les données des autres
Un bug d’autorisation survient lorsque votre app permet à la mauvaise personne d’accéder à quelque chose alors qu’elle est connectée. C’est différent de l’authentification, qui prouve simplement qui est quelqu’un (connexion, mot de passe, lien magique). L’autorisation répond à une autre question : maintenant que vous êtes connecté, que pouvez‑vous faire et quels enregistrements sont les vôtres ?
Lorsque l’autorisation est même légèrement incorrecte, les conséquences sont rarement mineures. Un utilisateur peut voir les factures d’un autre client, modifier le profil de quelqu’un d’autre ou supprimer des enregistrements qu’il ne devrait même pas connaître. Dans les apps CRUD, c’est particulièrement dangereux parce que tout peut sembler normal dans l’interface tant que quelqu’un ne change pas une URL, ne modifie pas une requête dans le navigateur, ou n’appelle une route API non protégée.
Cela apparaît souvent dans les dashboards, panneaux d’administration et portails clients. Ces apps grandissent vite : nouveaux écrans, nouveaux endpoints, nouveaux filtres. Un filtre de locataire manquant dans une requête de table et soudain des enregistrements d’un autre compte apparaissent.
Un schéma courant derrière ces bugs est le glissement de privilèges. Les permissions s’étendent silencieusement avec le temps. On commence par « les utilisateurs voient leurs propres éléments », puis on ajoute des outils de support, une vue admin, un endpoint d’export. Chaque étape ajoute un nouvel endroit où les vérifications peuvent dériver.
Un exemple réaliste : un portail client dispose d’un bouton « Télécharger le reçu ». L’endpoint prend un ID de reçu. Si le serveur ne vérifie que « l’utilisateur est connecté » mais pas « le reçu appartient à ce locataire », un utilisateur peut deviner ou réutiliser un ID et télécharger le reçu de quelqu’un d’autre.
Ces bugs survivent parce qu’un des basiques manque :
- une règle claire de propriété (utilisateur, équipe, ou locataire)
- des vérifications cohérentes à chaque lecture et écriture
- des tests qui tentent volontairement des accès inter‑comptes
Les équipes rencontrent souvent cela avec des prototypes générés par IA. L’authentification fonctionne, mais les règles d’autorisation ne sont pas appliquées de manière cohérente entre routes et requêtes. C’est là que « ça marchait dans la démo » se transforme en fuite de données en production.
Rôles, permissions et locataires - un modèle simple
La plupart des fuites de données surviennent parce que l’app ne se met pas d’accord sur une question simple : qui est cet utilisateur, et que peut‑il faire maintenant ?
Commencez par nommer les éléments d’identité que votre app doit porter sur chaque requête :
- ID utilisateur : la personne qui fait la requête.
- Rôle : le type d’accès qu’il a (lecteur, éditeur, admin).
- ID locataire : l’organisation/espace de travail/projet auquel il appartient.
Un contrôle de rôle répond à « Pouvez‑vous faire cette action ? ». Le scoping de locataire répond à « Sur quels enregistrements pouvez‑vous agir ? ». Vous avez généralement besoin des deux.
Par exemple, role = editor peut autoriser « modifier des factures ». Mais sans scoping de locataire, une requête comme « mettre à jour une facture par id » peut modifier une facture dans un autre espace de travail. L’utilisateur avait la permission, mais pas pour ce locataire.
Vérifications de rôle vs scoping de locataire
Les vérifications de rôle sont généralement simples : cet utilisateur peut‑il supprimer, peut‑il inviter des coéquipiers, peut‑il accéder à l’écran de facturation. Le scoping de locataire est la rambarde qui maintient chaque lecture et écriture à l’intérieur de la bonne organisation/espace de travail.
Un moyen mnémotechnique :
- Rôle décide de ce que vous pouvez faire.
- Locataire décide où vous pouvez le faire.
Le piège « admin »
« Admin » est là où beaucoup d’apps deviennent négligentes. Il y a une grande différence entre :
- Admin de locataire : peut gérer les utilisateurs et les paramètres à l’intérieur de son propre espace de travail.
- Admin global : peut accéder à tout à travers tous les locataires (rare, généralement personnel interne).
Si votre code traite tout admin comme global, un admin client normal peut finir par voir les données d’autres clients. C’est particulièrement courant quand « admin » est implémenté comme un simple flag sans préciser le périmètre.
Encore un avertissement : les restrictions uniquement dans l’UI ne sont pas de la sécurité. Cacher des boutons aide l’utilisabilité, mais ne protège pas les données. Si une route API accepte une requête, un utilisateur peut toujours l’appeler directement, même si l’UI n’affiche jamais l’option.
Où l’autorisation doit être appliquée
L’autorisation n’est pas une vérification que vous ajoutez « quelque part dans le backend ». Dans la plupart des fuites, une équipe avait bien une vérification, mais elle vivait au mauvais endroit ou ne couvrait qu’une couche.
Pensez l’application des règles comme une pile. Chaque couche bloque un type d’erreur différent, surtout dans du code produit rapidement où des handlers sont copiés et modifiés.
Pensez en couches (pas un seul garde)
Commencez au bord, là où les requêtes entrent dans votre système. Si un endpoint ne doit pas être appelable par un rôle, bloquez‑le avant tout travail. Cela évite les problèmes « je peux frapper l’URL directement ».
Ensuite, faites respecter l’accès à l’enregistrement spécifique. Savoir qu’une personne est connectée ne suffit pas. Vous devez prouver que l’enregistrement appartient à son locataire (ou qu’il a une raison trans‑locataire valide, comme un rôle de support interne).
Enfin, contrôlez ce qu’il peut voir ou changer dans cet enregistrement. Beaucoup d’apps limitent quelles lignes sont retournées mais fuient encore des champs sensibles (notes internes) ou acceptent des modifications sur des champs contrôlés par le serveur (role, plan, tenantId).
Une façon pratique de placer les vérifications :
- Accès route : qui peut appeler cet endpoint du tout
- Accès enregistrement : quel(s) item(s) spécifique(s) ils peuvent lire ou modifier
- Accès action : ce qu’ils peuvent faire (lire vs éditer vs supprimer vs exporter)
- Accès champ : quelles propriétés sont retournées ou acceptées
Une règle qui attrape la plupart des fuites
Supposez que les clients ne sont pas fiables, même votre propre frontend. Si une requête inclut un ID, un tenantId, ou un rôle, traitez‑le comme un indice, pas comme un fait. Le serveur doit dériver l’identité et le locataire depuis la session ou le token, puis appliquer cela à chaque requête et écriture.
Lors de la revue de code, cherchez les endroits où il n’y a qu’une seule couche. Si une route retourne des données, demandez : avons‑nous appliqué l’accès au niveau route, enregistrement, action et champ, ou n’avons‑nous fait qu’une seule vérification en espérant que cela couvre tout ?
Commencez par une carte des permissions que vous pouvez suivre
La plupart des bugs d’autorisation commencent comme un problème administratif. Personne ne peut répondre, en un seul endroit, « Qui peut faire quoi, sur quels enregistrements ? » Alors les vérifications sont ajoutées ad hoc, les routes dérivent, et les privilèges s’étendent lentement.
Une carte des permissions est une référence en langage clair que vous pouvez garder ouverte pendant l’audit des routes et des requêtes. Gardez‑la assez courte pour qu’un collègue non technique puisse la lire et repérer une règle étrange.
1) Écrivez la table rôles→actions (sans jargon)
Commencez par les rôles que vous avez réellement en production, pas ceux que vous prévoyez d’avoir. Mappez-les ensuite aux actions avec des verbes simples : voir, créer, éditer, supprimer, inviter, exporter, changer la facturation.
| Rôle | Peut voir | Peut créer | Peut éditer | Peut supprimer | Peut gérer les utilisateurs |
|---|---|---|---|---|---|
| Membre | Ses propres éléments | Oui | Ses propres éléments | Non | Non |
| Manager | Éléments de l’org | Oui | Éléments de l’org | Limité | Inviter des membres |
| Admin | Éléments de l’org | Oui | Éléments de l’org | Oui | Complet |
Si vous ne pouvez pas décrire une règle sans exceptions, c’est un signe qu’il vous faut un rôle supplémentaire ou un concept comme « propriétaire ».
2) Marquez chaque frontière de locataire et la clé qui la scope
Beaucoup d’apps ont plus d’une frontière : compte, org, workspace, projet. Notez chacune et choisissez la clé de scoping correspondante (par ex. org_id ou workspace_id). Ensuite, listez chaque ressource et la clé de locataire qui doit toujours être présente.
Quand vous faites cela, concentrez‑vous sur trois questions :
- Qu’est‑ce qui scope chaque ressource (org_id, workspace_id, project_id) ?
- D’où vient ce scope (session, token, URL, body de la requête) ?
- Quelles frontières ne doivent jamais être franchies ?
Enfin, définissez le « propriétaire » par ressource. « Propriétaire » n’est pas universel. Un commentaire peut être possédé par son créateur, une tâche par son assigné, une facture par le compte.
Un exemple concret : si « propriétaire » d’un document signifie « créateur », alors un manager ne devrait pas automatiquement éditer chaque document à moins que votre table indique que les managers peuvent éditer tous les documents de l’organisation. Ce détail évite une erreur courante : utiliser des vérifications de rôle pour éviter le scoping de locataire.
Audit pas à pas : routes API et handlers serveur
Les bugs d’autorisation se cachent souvent dans des endroits ennuyeux : les routes oubliées, le handler qui « met juste à jour un enregistrement », ou l’endpoint admin qui n’a jamais eu de vraies vérifications. Un audit est principalement un inventaire plus de la discipline.
1) Inventoriez chaque route (oui, toutes)
Listez chaque route API que votre app expose, y compris les endpoints internes, admin et « temporaires » ajoutés pendant le prototypage. Ces expériences collent souvent et restent atteignables.
Choisissez une source de vérité (fichier router, dossier routes du framework, ou config API gateway) et créez un tableau simple. Si vous trouvez des routes plus utilisées, marquez‑les pour suppression, mais auditez‑les d’abord.
2) Pour chaque route, notez : acteur, action, ressource, frontière de locataire
Pour chaque route, écrivez une phrase en clair :
- Acteur : qui appelle (utilisateur connecté, admin org, job système) ?
- Action : que font‑ils (lire, créer, mettre à jour, supprimer) ?
- Ressource : quel objet est touché (facture, projet, utilisateur, fichier) ?
- Frontière de locataire : quel conteneur doit matcher (org_id, workspace_id, account_id) ?
Si vous ne pouvez pas décrire la règle en une phrase, le code est généralement incohérent.
3) Vérifiez le scope du locataire côté serveur, pas côté client
Vérifiez que le handler dérive le locataire depuis la session authentifiée (ou les claims du token côté serveur), pas depuis les champs du body de la requête ou les query params.
Un signal d’alerte courant : la requête inclut orgId et le serveur lui fait confiance. Un pattern plus sûr est : lire org_id depuis la session utilisateur, puis l’imposer dans chaque requête et mutation.
4) Confirmez que les écritures sont aussi scoping (pas seulement les lectures)
Les équipes scoperent souvent les pages de liste mais oublient les updates et deletes. Cherchez des endpoints comme :
PATCH /projects/:idDELETE /invoices/:idPOST /members/:id/role
Si le handler met à jour par id seulement, c’est un risque instantané de cross‑tenant. La vérification doit être : « enregistrement avec cet id ET ce tenant appartient à cet acteur. »
5) Surveillez les routes qui acceptent des IDs et récupèrent les enregistrements « à nu »
Toute route prenant un id est une zone sensible. Le pattern dangereux est :
- récupérer par
id - vérifier quelque chose vaguement (ou rien)
- retourner ou muter
Au lieu de cela, appliquez l’autorisation comme partie intégrante de la recherche. Si l’enregistrement n’est pas dans le locataire de l’acteur (ou si l’acteur n’a pas la permission), la recherche doit échouer.
Audit pas à pas : requêtes DB et filtres ORM
L’autorisation peut sembler correcte au contrôleur, puis se briser silencieusement au niveau base de données. Si une requête peut retourner des enregistrements d’un autre locataire, l’app finira par les afficher, peut‑être dans la recherche, les exports, ou des cas limites non testés.
Commencez par trouver chaque endroit où votre app lit « plusieurs lignes » (pages de liste, recherche, tables admin, jobs en arrière‑plan). Pour chaque requête, posez‑vous une question : où le filtre de locataire est‑il appliqué, et peut‑il être contourné ?
1) Auditez les requêtes de liste (plusieurs lignes)
Ouvrez chaque endpoint de liste et suivez jusqu’à l’appel ORM. Les contraintes de locataire doivent faire partie de la requête à chaque fois, pas ajoutées après en mémoire.
Une checklist qui attrape la plupart des fuites :
- Le scope locataire est dans la requête DB (pas filtré après récupération).
- La pagination utilise la même requête scoppée (les requêtes de count et de données correspondent).
- Les termes de recherche sont combinés avec le scope locataire en utilisant AND, pas OR.
- La logique de tri et de curseur ne retombe pas sur une requête de base non scoppée.
- Les « include related data » ne chargent pas d’enfants inter‑locataires.
2) Auditez les requêtes de détail (ligne unique)
Les endpoints de détail ne doivent jamais rechercher par id seul. La recherche doit inclure tenantId et id (ou une autre clé unique liée au locataire). Si votre ORM a des helpers comme findUnique(id), considérez‑les suspects à moins que la clé unique n’inclue tenantId.
Privilégiez findFirst where tenantId = X and id = Y plutôt que find by id then check tenant later. Le second pattern s’oublie facilement dans un handler.
3) Joins, exports et requêtes « spéciales »
Les joins sont un endroit commun où le scoping de locataire disparaît. Une requête peut commencer scoppée, puis joindre une autre table et filtrer sur le mauvais champ tenant (ou ne pas filtrer du tout).
Vérifiez aussi les reports, exports et jobs en arrière‑plan. Ils contournent souvent le code API normal et ont donc besoin des mêmes règles de scoping au niveau requête.
Pièges courants qui causent la dérive des privilèges
La dérive des privilèges n’arrive généralement pas parce que quelqu’un écrit « allow all ». Elle arrive parce que des petits raccourcis s’additionnent : une route fait confiance à l’UI, une autre assume que « admin » est global, une troisième oublie un job en arrière‑plan.
Erreur 1 : Faire confiance au client (flags UI, boutons cachés)
Si un utilisateur peut modifier une requête, il peut modifier tout ce que le navigateur envoie. Un bouton « Supprimer » caché ou un flag client role: "admin" n’est pas une protection. Le serveur doit décider en fonction de l’identité connectée.
Une version courante : l’UI cache « Éditer facture » sauf si vous êtes manager, mais la route API ne vérifie que la connexion. N’importe qui peut appeler la route directement et mettre à jour la facture d’un autre.
Erreur 2 : Utiliser isAdmin sans scoping
« Admin » n’a pas de sens sans périmètre. Dans les apps multi‑locataires, la plupart des rôles doivent être scoppés au locataire. Le piège est d’écrire une logique du type « if isAdmin, allow », et d’accorder accidentellement l’accès à travers tous les locataires.
Un contrôle mental plus sûr : chaque décision d’autorisation doit répondre à deux questions, « qui est cet utilisateur ? » et « à quel locataire ces données appartiennent‑elles ? » Si l’une des réponses est floue, vous êtes à un refactor de l’accès cross‑tenant.
Erreur 3 : Vérifier après avoir chargé l’enregistrement
Beaucoup de fuites arrivent parce que le code récupère d’abord un enregistrement, puis vérifie si l’utilisateur y a droit. Même si vous bloquez la réponse, vous pouvez encore fuir des informations via des effets secondaires comme les différences d’erreur, le timing, ou les données liées chargées en chemin.
Privilégiez les vérifications qui empêchent la récupération de l’enregistrement en incluant les règles de locataire et de propriété directement dans la requête.
Erreur 4 : Oublier les « portes latérales » (jobs, webhooks, téléchargements)
Les jobs en arrière‑plan, tâches cron, handlers de webhooks et endpoints de téléchargement de fichiers sautent souvent le middleware habituel et se retrouvent avec des vérifications plus faibles. Si un job traite « toutes les factures » sans filtre de locataire, il peut envoyer ou exporter les données clients erronées.
Pour ces chemins, assurez‑vous de pouvoir répondre : authentifie‑t‑il l’appelant (ou valide‑t‑il le webhook), applique‑t‑il le scoping de locataire sur chaque requête, et logge‑t‑il ce qu’il a touché (tenant id, record id, acteur) ?
Erreur 5 : Helpers partagés aux valeurs par défaut floues
Un helper comme getUserProjects(userId) semble sûr jusqu’à ce que quelqu’un le réutilise dans un écran admin en supposant qu’il renvoie « tous les projets ». Pire, un helper peut par défaut ne pas filtrer par locataire quand tenantId est manquant.
Les bons helpers échouent bruyamment. Si tenantId est requis pour la sécurité, rendez‑le obligatoire dans la signature de la fonction et throw si c’est manquant.
Exemple réaliste : une mauvaise route, une grosse fuite
Imaginez un rôle d’agent de support. Il devrait pouvoir voir des tickets de support, mais uniquement pour son organisation (son locataire). Cela semble simple, mais il suffit d’un endpoint négligent pour casser la règle.
Voici l’erreur : l’API a une route comme GET /api/tickets/:ticketId. Le handler vérifie que l’utilisateur est connecté, puis récupère le ticket par ID. Il ne vérifie jamais le locataire.
// Unsafe: fetches by ID only
const ticket = await db.ticket.findUnique({
where: { id: ticketId }
});
return ticket;
Pourquoi cela fuit des données : les IDs de ticket apparaissent souvent dans des endroits accessibles aux utilisateurs, comme les URLs du navigateur, notifications email, logs des outils de support, ou CSV exportés. Même sans cela, beaucoup d’apps utilisent des IDs prévisibles (nombres incrémentaux, UUID courts copiés depuis l’UI). Un utilisateur curieux ou malveillant peut échanger un ID contre un autre et voir un ticket d’une autre org.
C’est l’un des échecs les plus courants : le code suppose que connaître un ID est la preuve que vous devez voir l’enregistrement.
Un handler plus sûr fait deux choses différemment :
- Scope la requête au locataire (org) depuis la session.
- Vérifie le rôle pour l’action (visualiser un ticket).
// Safer: enforce role + tenant scoping
if (user.role !== "support_agent") throw new Error("Forbidden");
const ticket = await db.ticket.findFirst({
where: { id: ticketId, orgId: user.orgId }
});
if (!ticket) throw new Error("Not found");
return ticket;
Remarquez le comportement « Not found ». Il évite de confirmer qu’un ticket existe dans une autre org.
Pour vérifier la correction, gardez le test simple :
- Créez deux orgs, Org A et Org B.
- Créez un ticket dans Org B.
- Connectez‑vous en tant qu’Agent de Support dans Org A.
- Appelez l’endpoint en utilisant le
ticketIdd’Org B. - Confirmez que vous obtenez « Not found » (ou 404), et qu’aucune donnée du ticket n’est renvoyée.
Vérifications rapides à exécuter avant une release
La plupart des bugs d’autorisation se révèlent dans la dernière ligne droite : une nouvelle route, un raccourci admin « utile », ou une requête qui a oublié le scoping de locataire. Ces vérifications sont simples et reproductibles.
Le test fumée à deux comptes (10 minutes)
Créez deux comptes de test qui semblent normaux mais appartiennent à des locataires différents (Société A et Société B). Donnez‑leur des données réalistes pour distinguer ce qui appartient à qui.
Puis mélangez volontairement les identifiants :
- Copiez un ID d’enregistrement du locataire A et essayez de le lire depuis le locataire B.
- Essayez une mise à jour avec l’ID du locataire A en étant connecté comme locataire B.
- Essayez une suppression avec l’ID du locataire A en étant connecté comme locataire B.
- Si votre app utilise la suppression douce, testez aussi la restauration.
- Répétez pour les objets enfants (commentaires, factures, fichiers) qui peuvent être scoppés différemment.
Si l’un de ces tests réussit ou renvoie de vraies données, vous avez probablement des filtres de locataire manquants ou une vérification de rôle qui ne s’exécute qu’en UI.
N’oubliez pas les fonctionnalités bulk et les portes latérales
Les fuites surviennent souvent hors des écrans CRUD principaux. Une endpoint de liste peut être scoppée, mais l’export non. Un téléchargement de fichier peut sauter les vérifications parce que c’est « juste une URL ».
Passez rapidement en revue :
- Pages de liste avec filtres, recherche, tri et pagination (essayez de chercher une valeur connue de l’autre locataire).
- Endpoints d’export (CSV, PDF, rapports) et jobs en arrière‑plan qui les génèrent.
- Téléchargements et aperçus de fichiers (URLs signées, IDs d’attachement, endpoints d’image).
- Journaux d’activité, dashboards admin et widgets « éléments récents ».
- Toute route acceptant un ID dans le chemin, même si l’UI ne l’expose jamais.
Confirmez aussi que vos rôles admin sont scoppés comme prévu. Un « admin de locataire » ne doit pas agir comme un « admin global » parce que c’était plus simple.
Étapes suivantes : rendre l’autorisation difficile à casser
Les échecs d’autorisation n’arrivent presque jamais parce que les gens ne s’en soucient pas. Ils arrivent parce que les vérifications sont dispersées, les filtres de locataire sont faciles à oublier, et de nouvelles fonctionnalités sont livrées plus vite que les règles ne sont mises à jour. L’objectif est de rendre le chemin sûr aussi facile que possible.
Mettez une garde devant tout
Utilisez une couche d’autorisation cohérente partout : middleware, helper de policy, ou service que chaque handler appelle avant d’effectuer le travail. Si vous devez vous souvenir quelles routes « ont besoin de vérifs », vous en oublierez une.
Une bonne règle : les handlers de route ne devraient pas contenir de logique de permission personnalisée. Ils devraient poser une question claire à la couche de policy (par ex. « Cet utilisateur peut‑il mettre à jour cette facture ? ») puis continuer.
Changements qui réduisent rapidement les erreurs :
- Créez un helper de policy (ou middleware) par ressource : read, create, update, delete.
- Faites du scoping de locataire le comportement par défaut (par ex. un helper de requête scoppée qui applique toujours tenantId).
- Refusez par défaut quand des données sont manquantes ou ambiguës (pas de locataire, pas de rôle, pas de propriété).
- Loggez les refus d’autorisation avec assez de contexte pour déboguer (utilisateur, locataire, ressource, action).
Intégrez le scoping de locataire dans l’accès aux données
Centralisez le scoping de locataire pour qu’il soit dur à oublier. Le meilleur endroit est là où les requêtes sont construites, pas là où les réponses sont renvoyées.
Par exemple, au lieu d’écrire where: { id } à plusieurs endroits, exposez un helper qui inclut déjà tenantId. Si un développeur essaie de le contourner, cela devrait paraître étrange en revue de code.
Les tests à forte valeur détectent les régressions qui comptent le plus :
- Lecture inter‑locataire échoue (Utilisateur A ne peut pas récupérer l’enregistrement de l’utilisateur B par ID).
- Écriture inter‑locataire échoue (Utilisateur A ne peut pas mettre à jour/supprimer l’enregistrement de l’utilisateur B).
- Downgrade de rôle est sûr (un utilisateur perdant des droits admin ne garde pas l’accès admin).
- La création est scoppée (les nouveaux enregistrements reçoivent le tenant courant).
Si vous avez hérité d’une base de code générée par IA et que vous n’êtes pas sûr que le scoping de locataire et les vérifications de rôle soient appliqués de façon cohérente, un audit ciblé peut vous faire gagner des jours de recherches. FixMyMess (fixmymess.ai) est spécialisé dans le diagnostic et la réparation de ce type de lacunes d’autorisation, en particulier les handlers « id‑only » et les requêtes non scoppées qui paraissent correctes jusqu’à ce que de vrais utilisateurs touchent la production.
Questions Fréquentes
Pourquoi des utilisateurs voient les données d’autres personnes même si la connexion fonctionne ?
C’est un problème d’autorisation, pas d’authentification. L’utilisateur peut être correctement connecté, mais votre serveur ne vérifie pas systématiquement que l’enregistrement demandé appartient bien à son utilisateur/équipe/locataire avant de le renvoyer.
Quelle est la différence entre authentification et autorisation ?
L’authentification répond à « qui êtes-vous ? ». L’autorisation répond à « que pouvez‑vous faire et quels enregistrements vous appartiennent ? ». La plupart des fuites inter-comptes surviennent lorsque l’app vérifie seulement que l’utilisateur est connecté, puis récupère des données par ID sans vérifier la propriété ou le périmètre du locataire.
Ai-je besoin de vérifications de rôle, de scoping par locataire, ou des deux ?
Les vérifications de rôle décident des actions qu’un utilisateur peut entreprendre (par ex. « peut modifier des factures »). Le scoping par locataire décide où il peut effectuer ces actions (par ex. « uniquement dans cet espace de travail »). Vous avez généralement besoin des deux : rôle pour le « can », locataire pour le « where ».
Quelles endpoints risquent le plus de fuir des données inter-locataires ?
Toute route qui accepte un ID est un point chaud, en particulier les routes de téléchargement, d’export et de détail. Si le handler récupère un enregistrement par id seul, un utilisateur peut échanger les IDs et potentiellement accéder aux données d’un autre locataire.
Si l’interface cache les fonctions admin, est-ce suffisant pour la sécurité ?
Non. Cacher des boutons améliore seulement l’UX ; ça ne protège pas l’API. Il faut supposer que n’importe qui peut appeler vos endpoints directement, donc le serveur doit appliquer les permissions et la propriété du locataire sur chaque lecture et écriture.
Qu’est‑ce que le « piège admin » et comment l’éviter ?
« Admin » doit avoir un périmètre. Un admin de locataire ne devrait gérer que son propre locataire ; un admin global peut tout voir et doit rester rare et contrôlé. Si votre code traite tout admin comme global, vous pouvez accorder par erreur un accès inter-locataires.
Pourquoi est‑il risqué de charger un enregistrement puis de vérifier l’accès après ?
Parce que le code récupère d’abord l’enregistrement, puis vérifie l’accès après. Même si vous bloquez la réponse, des fuites peuvent survenir via des effets secondaires : différences d’erreur (404 vs 403), timing, ou données reliées chargées au passage. Le modèle sûr est d’inclure les règles de locataire et de propriété directement dans la requête à la base, pour que les enregistrements non autorisés ne soient jamais récupérés.
Le serveur doit‑il faire confiance au tenantId ou au rôle envoyés depuis le client ?
Dérivez l’identité et le locataire à partir de la session côté serveur ou des claims du token, puis appliquez-les à chaque requête et mutation. Traitez tout tenantId, role ou userId venant du client comme un indice au mieux, pas comme une vérité.
Quelle est la manière la plus rapide de tester pour des fuites d’autorisation ?
Créez deux comptes dans deux locataires distincts avec des données clairement différentes. Connectez‑vous en tant que locataire B et tentez de lire, mettre à jour et supprimer des enregistrements du locataire A en réutilisant les IDs. Si quelque chose réussit ou renvoie de vraies données, il y a une faille de scoping à corriger avant la mise en production.
Pourquoi les apps CRUD générées par IA ont-elles tant de bugs d’autorisation, et que puis‑je faire ?
Les prototypes générés par IA activent souvent l’authentification rapidement mais appliquent l’autorisation de façon incohérente entre routes et requêtes, surtout dans des handlers copiés ou des endpoints temporaires. Si vous héritez d’une telle base de code et voulez la rendre sûre pour la production rapidement, FixMyMess (fixmymess.ai) peut réaliser un audit ciblé et réparer les handlers id-only, les requêtes sans scope et les erreurs de rôle/locataire, souvent en 48–72 heures après un audit de code gratuit.