L’isolation des tenants est une discipline de murs au sein des systèmes partagés : des contrôles qui scellent chaque tenant à l’écart de tous les autres. Le point que la plupart des explications enterrent mérite le premier paragraphe : l’isolation n’est ni de l’authentification ni de l’autorisation. Un utilisateur parfaitement connecté, doté du bon rôle, peut quand même lire les données d’un concurrent si rien ne restreint la requête à son tenant — l’isolation est la troisième couche, celle qui décide dans l’univers de qui chaque opération se déroule.
Points clés
| Question | Réponse |
|---|---|
| Ce que c’est | Les garanties qu’aucun tenant ne peut atteindre les données ou les ressources d’un autre |
| À ne pas confondre avec | L’authentification (qui) et l’autorisation (quoi) — l’isolation, c’est à qui |
| Où placer les murs | Lignes de la base, caches, files d’attente, stockage, tokens — chaque couche partagée |
| Le mode de défaillance | Une requête, un job ou une clé de cache sans portée de tenant = une fuite de données entre tenants |
| La norme | Appliquer dans la couche de données ; tester de façon adversariale ; ne jamais faire confiance aux ID de tenant envoyés par le client |
Le bug, et le mur qui y survit
-- Le bug auquel l'isolation doit survivre : une requête qui a oublié son tenant
SELECT * FROM invoices WHERE id = $1; -- renvoie la facture de n'importe qui
-- Avec le mur dans la couche de données, le même bug ne renvoie rien :
ALTER TABLE invoices ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_wall ON invoices
USING (tenant_id = current_setting('app.tenant')::uuid);
Dans les bases de données documentaires, le mur se construit avec des rôles et un contrôle d’accès par objet — le tenant est un rôle, et chaque ligne lui est scellée au moment de l’écriture :
// JavaScript / Node.js — Back4app JS SDK
// Provisioning a tenant boundary: a role is the tenant, membership is access
const tenantRole = new Parse.Role('tenant-acme', new Parse.ACL());
tenantRole.getUsers().add(adminUser);
await tenantRole.save();
// Every acme row from now on: readable and writable by the role only
const doc = new Parse.Object('Project', { name: 'Q3 Launch' });
const acl = new Parse.ACL();
acl.setRoleReadAccess('tenant-acme', true);
acl.setRoleWriteAccess('tenant-acme', true);
doc.setACL(acl);
await doc.save(); // Flutter / Dart — Back4app Flutter SDK
// Every tenant row: readable and writable by the tenant role only
final acl = ParseACL();
acl.setRoleReadAccess('tenant-acme', true);
acl.setRoleWriteAccess('tenant-acme', true);
final doc = ParseObject('Project')
..set('name', 'Q3 Launch')
..setACL(acl);
await doc.save(); // invisible to every other tenant, enforced server-side // iOS / Swift — Back4app Swift SDK
// Every tenant row: readable and writable by the tenant role only
var acl = ParseACL()
acl.setReadAccess(roleName: "tenant-acme", value: true)
acl.setWriteAccess(roleName: "tenant-acme", value: true)
var doc = Project()
doc.name = "Q3 Launch"
doc.ACL = acl
doc.save { _ in } // invisible to every other tenant, enforced server-side // Android / Kotlin — Back4app Android SDK
// Every tenant row: readable and writable by the tenant role only
val acl = ParseACL().apply {
setRoleReadAccess("tenant-acme", true)
setRoleWriteAccess("tenant-acme", true)
}
val doc = ParseObject("Project").apply {
put("name", "Q3 Launch")
setACL(acl)
}
doc.saveInBackground() // invisible to every other tenant, enforced server-side La pile de contrôle
Chaque couche rattrape ce que la précédente laisse passer : le token établit l’identité du tenant côté serveur, le code applicatif restreint la portée par habitude, la couche de données impose la règle par politique, et l’infrastructure place sous namespace tout le reste de ce qui est partagé. La cheat sheet de l’OWASP est la checklist de référence pour toute la pile.
Isolation vs. authentification vs. autorisation
| Question traitée | Mécanisme | À quoi ressemble la défaillance |
|---|---|---|
| Qui êtes-vous ? (authentification) | Connexion, sessions, tokens | Un imposteur entre |
| Que pouvez-vous faire ? (autorisation) | Rôles, permissions | Un utilisateur dépasse son rôle |
| À qui appartiennent ces données ? (isolation) | Portée de tenant + murs dans la couche de données | Un utilisateur légitime lit un autre tenant |
La troisième ligne est celle qui fait les gros titres, parce qu’elle passe tous les tests que définissent les deux premières : l’attaquant se connecte légitimement, utilise des opérations autorisées — et traverse un mur manquant. Les vulnérabilités entre tenants emblématiques de l’ère du cloud (la classe ChaosDB de découvertes de recherche, où un tenant pouvait obtenir l’accès aux bases de données d’autres tenants) étaient toutes des défaillances de la troisième ligne, dans des systèmes aux première et deuxième lignes irréprochables.
D’où viennent réellement les fuites
- Le filtre oublié — une requête sans sa portée de tenant ; la raison pour laquelle les murs ont leur place dans la couche de données, pas dans la mémoire des développeurs.
- L’IDOR — des ID séquentiels ou devinables récupérés sans contrôle du tenant ; changez un ID, lisez le dossier d’un inconnu.
- L’exécution hors contexte — jobs en arrière-plan, webhooks, tâches planifiées et exports de données exécutés avec des identifiants trop larges et sans contexte de tenant.
- Les services partagés sans portée — clés de cache, index de recherche et chemins de fichiers sans le préfixe du tenant ; le mur de la base tient pendant que le cache fuit.
- Les pipelines parallèles — l’analytique et le reporting qui lisent directement la base de données, sous tous les contrôles applicatifs.
- Le tenant confié au client — un ID de tenant accepté depuis le corps de la requête au lieu d’être dérivé de la session ; la manière la plus polie qui soit de distribuer les données des autres tenants.
Isolation de sécurité vs. noisy neighbors
Même mot, deux problèmes. L’isolation de sécurité tient le tenant A à l’écart des données du tenant B. L’isolation de performance — le problème du noisy neighbor (voisin bruyant) — tient l’import massif du tenant A à l’écart de la latence du checkout du tenant B ; elle se résout par des quotas, du rate limiting et du partitionnement, et elle est traitée côté architecture de ce sujet. Un système peut être étanche et laisser malgré tout un tenant affamer les autres ; prévoyez un budget pour les deux, et ne laissez pas une discussion sur les quotas se faire passer pour une revue de sécurité.
Tester l’isolation des tenants
La passe adversariale à deux tenants, automatisée en CI : créez les tenants A et B, puis tentez tous les croisements — les ID d’objets de B via la session de A sur chaque endpoint (le balayage IDOR), le token de A contre les ressources de B, les surfaces hors du chemin principal (exports, panneaux d’administration, jobs) avec le contexte de chaque tenant, et une inspection des clés de cache, des URL de fichiers et des résultats de recherche à la recherche d’une portée de tenant manquante. Ajoutez le cas du contexte non défini : aucun tenant dans la session doit signifier aucune ligne, jamais toutes les lignes. Une isolation qui n’a pas été attaquée en CI est une hypothèse munie d’un certificat de conformité.
Cas d’usage courants
- SaaS B2B. Chaque workspace est un tenant ; l’isolation est la promesse produit sous chaque fonctionnalité.
- Plateformes qui hébergent des apps clientes. Deux altitudes à la fois — la plateforme isole les apps les unes des autres, chaque app isole ses propres tenants.
- Offres entreprise et secteurs réglementés. Des exigences contractuelles d’isolation traduites en murs plus solides — clés par tenant, ressources dédiées — pour les comptes qui en ont besoin.
- Agences et produits en marque blanche. Un seul déploiement, de nombreuses organisations clientes, chacune scellée.
- Plateformes internes multi-équipes. Les départements comme tenants ; un modèle de menace plus clément, une mécanique identique.
Quel niveau d’isolation ? Matrice de décision
| Mutualisé + murs dans la couche de données quand… | Séparation plus forte quand… |
|---|---|
| Beaucoup de petits tenants, sensibilité standard | Les contrats spécifient des exigences d’isolation |
| Le coût par tenant doit rester proche de zéro | Les données d’un tenant exigent leurs propres clés ou leur propre région |
| Les murs sont appliqués (RLS/ACL) et testés | Les arguments de rayon d’impact l’emportent sur l’économie de densité |
| Un seul cycle de mise à jour doit couvrir tout le monde | La restauration par tenant est une fonctionnalité promise |
| L’équipe peut maintenir des tests adversariaux | Les auditeurs veulent des frontières qu’ils peuvent désigner du doigt |
Le cadrage honnête : un modèle mutualisé avec des murs appliqués et testés est une isolation légitime — l’essentiel du secteur fonctionne ainsi. Faites monter des tenants individuels sur l’échelle de la séparation quand leurs exigences, et non la mode, le demandent.
Limites et trade-offs
- L’isolation est transversale, pour toujours. Chaque nouvelle fonctionnalité — cache, file d’attente, export, recherche — repose la question du tenant ; la discipline n’est jamais terminée.
- Les murs dans la couche de données ont leurs petites lignes opérationnelles. Contexte de session vs. pooling de connexions, rôles de contournement des politiques et modes de dump — l’article sur la sécurité au niveau des lignes les recense.
- Le rayon d’impact partagé survit à l’exactitude. Une isolation logique parfaite partage toujours des domaines de défaillance — un mauvais déploiement touche tous les tenants ; seule la séparation physique change cela.
- Les tests sont le coût absent du budget. La suite à deux tenants est un vrai travail d’ingénierie ; la sauter ramène “appliqué” au rang de “supposé”.
- Des murs plus solides coûtent de la densité. Clés par tenant, silos et ressources dédiées sacrifient tous l’économie qui rendait le partage attractif — réservez-les aux tenants qui en ont besoin.
L’isolation des tenants sur Back4app
Back4app est une plateforme open-source de Backend as a Service (BaaS) qui combine une base de données gérée, des API REST et GraphQL générées automatiquement, l’authentification, le stockage de fichiers et des fonctions serverless avec Cloud Code. L’isolation y part de la couche de données par construction : les rôles définissent le tenant, l’ACL de chaque objet le scelle à ce rôle et les permissions au niveau de la classe encadrent le schéma — le tout appliqué côté serveur sur chaque chemin, SDK, REST, GraphQL et dashboard confondus, si bien que le bug du filtre oublié n’a plus rien à oublier. La plateforme applique elle-même la même discipline un niveau plus haut, en isolant le backend de chaque app de celui de toutes les autres — et l’analyse d’ingénierie sur la sécurité au niveau des lignes montre le modèle complet en pratique.
Questions fréquentes
Qu'est-ce que l'isolation des tenants ?
L'ensemble des contrôles architecturaux qui empêchent un tenant d'un système partagé d'atteindre les données ou les ressources d'un autre tenant — les murs entre les appartements d'un même immeuble. Elle couvre chaque couche partagée : lignes de la base de données, caches, files d'attente, stockage de fichiers et calcul, chacune ayant besoin de sa propre frontière, limitée au tenant courant.
En quoi l'isolation des tenants diffère-t-elle de l'authentification et de l'autorisation ?
Un utilisateur peut être pleinement authentifié et correctement autorisé pour son rôle — et atteindre quand même les données d'un autre tenant si rien ne restreint la requête à son tenant. L'authentification prouve qui vous êtes ; l'autorisation décide des actions que vous pouvez effectuer ; l'isolation garantit dans l'univers de quel tenant ces actions se déroulent. C'est une couche à part entière, et considérer que connexion plus rôles suffisent est la racine de la plupart des bugs entre tenants.
Qu'est-ce qui provoque les fuites de données entre tenants ?
Une liste courte et stable : des requêtes privées de leur filtre de tenant ; l'IDOR — des ID devinables récupérés sans restriction au tenant ; des jobs en arrière-plan, des webhooks et des exports exécutés hors du contexte du tenant ; des caches dont les clés n'incluent pas le tenant ; des pipelines d'analytique et de reporting qui contournent les contrôles applicatifs ; et la confiance accordée à un identifiant de tenant fourni par le client au lieu de le dériver de la session côté serveur.
Le problème du noisy neighbor est-il la même chose que l'isolation des tenants ?
Ce sont des cousins, pas le même problème. L'isolation de sécurité empêche un tenant d'accéder aux données d'un autre ; l'isolation de performance — le problème du noisy neighbor (voisin bruyant) — empêche la charge d'un tenant de dégrader celle de tous les autres, et se résout par des quotas, du throttling et du partitionnement. Les discussions les confondent régulièrement ; un système peut être parfaitement sûr et laisser malgré tout un tenant affamer les autres.
Quel modèle d'isolation les référentiels de conformité exigent-ils ?
Aucun des grands référentiels n'impose une architecture — ils sont fondés sur les résultats et exigent des mesures appropriées et démontrables. La séparation physique est généralement réclamée par les grands comptes et les contrats, pas par les régulateurs. Ce que les audits récompensent vraiment : une application des règles dans la couche de données, des frontières documentées et la preuve que l'isolation est testée plutôt que supposée.
Comment la sécurité au niveau des lignes applique-t-elle l'isolation des tenants ?
En faisant de la frontière du tenant une propriété de la table : des politiques filtrent chaque requête selon le contexte de tenant de la session, si bien qu'une requête qui oublie son filtre ne renvoie rien au lieu de tout renvoyer. L'équivalent dans les bases de données documentaires est le contrôle d'accès par objet — des ACL qui désignent le rôle du tenant — appliqué par la plateforme à chaque requête. Dans les deux cas, le mur tient même quand le code applicatif trébuche.
Comment tester l'isolation des tenants ?
De façon adversariale, avec deux tenants : échangez les ID d'objets entre eux sur chaque endpoint (la sonde IDOR), rejouez le token d'un tenant contre les ressources de l'autre, exercez les chemins qui contournent l'application principale — exports, panneaux d'administration, jobs en arrière-plan — et inspectez les clés de cache et les URL de fichiers à la recherche d'une portée de tenant manquante. Automatisez les tests négatifs en CI ; une isolation qui n'est pas testée n'est qu'une hypothèse.
Quelles couches ont besoin d'isolation en plus de la base de données ?
Tout ce qui est partagé : des clés de cache préfixées par le tenant, des topics de file d'attente et des consumer groups limités à chaque tenant, un stockage objet sous des préfixes par tenant avec les politiques d'accès correspondantes, des clés de chiffrement par tenant là où les contrats l'exigent, et des claims de tenant portés dans les tokens et validés à chaque requête. Le mur de la base de données est nécessaire, jamais suffisant.