Checkliste zur Tenant-Isolation für SaaS-Prototypen: Fallstricke vermeiden
Nutze diese Tenant-Isolation-Checkliste, um Multi-Tenant-Fallen in APIs, Storage, Background Jobs und Analytics zu finden und zu beheben, bevor dein SaaS-Prototyp live geht.

Warum Tenant-Isolation in SaaS-Prototypen scheitert
Ein Tenant-Datenleck ist leicht vorstellbar: Ein Kunde meldet sich an, klickt auf „Projekte“ und sieht den Projektnamen, eine Rechnung, eine Datei oder die Nutzerliste eines anderen Kunden. Manchmal ist es kleiner, etwa eine Autocomplete-Vorschlag, der den Kontakt einer anderen Firma enthält, oder eine Dashboard-Zahl, die stillschweigend Daten anderer Accounts einbezieht.
Das passiert in Prototypen, weil „Login funktioniert“ nicht dasselbe ist wie „Daten sind isoliert“. Viele schnell gebaute oder KI-generierte Builds sperren Seiten hinter Authentifizierung, wenden aber nicht überall konsequent Tenant-Prüfungen an, wo Daten gelesen, geschrieben oder verarbeitet werden. Ein Endpoint filtert nach Nutzer-ID, ein anderer vergisst den Filter komplett. Ein Hintergrundjob läuft ohne Tenant-Kontext. Ein Cache-Key wird geteilt. Die UI sieht korrekt aus, aber die zugrunde liegenden Regeln sind uneinheitlich.
Einige häufige Wege, wie frühe Multi-Tenant-SaaS-Apps Daten leaken:
- API-Endpunkte akzeptieren eine Record-ID und geben sie zurück, ohne zu prüfen, ob sie zum Tenant des Aufrufers gehört
- Datenbankabfragen fehlen ein Tenant-Filter in einem Codepfad (oft Admin-Screens, Exporte, Suche)
- Objekt-Speicher-URLs oder Dateipfade sind nicht tenant-getrennt
- Hintergrundjobs verarbeiten „alle Datensätze“ statt „die Datensätze dieses Tenants“
- Analytics-Events sind falsch getaggt und vermischen Reports über Kunden hinweg
Die Kosten eines kleinen Lecks sind selten klein. Vertrauen sinkt schnell, Support-Anfragen steigen und Kundenabwanderung folgt. Bei personenbezogenen Daten kann ein Leak außerdem Meldepflichten, Vertragsprobleme oder Compliance-Kopfschmerzen auslösen.
Gute Isolation bedeutet, für einen nicht-technischen Gründer, ein klares Versprechen: Die Daten jedes Kunden verhalten sich so, als lägen sie in ihrer eigenen Box, obwohl du eine App betreibst. Eine praktische Tenant-Isolation-Checkliste sollte jeden Ort abdecken, an dem Daten sich bewegen: APIs, Datenbank, Dateien, Jobs, Cache und Analytics. Wenn du einen Prototyp geerbt hast, der „meist funktioniert“, sich aber riskant anfühlt, kann FixMyMess den Code auditieren und genau aufzeigen, wo Isolation bricht, bevor du weitere Kunden an Bord holst.
Multi-Tenancy-Grundlagen und die Grenzen, die du definieren musst
Single-Tenant bedeutet, jeder Kunde hat seine eigene isolierte App oder Datenbank. Multi-Tenant bedeutet, Kunden teilen sich dieselbe App (und oft dieselbe Datenbank) und dein Code muss Trennung garantieren. Prototypen starten oft „meistens korrekt“ und brechen dann stillschweigend die Isolation, wenn schnell ein Feature ausgeliefert wird.
Die erste Grenze, die du definieren musst, ist die Tenant-Identität: Wo erfährt die App, zu welchem Tenant diese Anfrage gehört? In den meisten SaaS-Apps sollte das aus dem authentifizierten Nutzerkontext (Token oder Session) kommen, der serverseitig verifiziert wird. Es sollte nicht aus etwas stammen, das der Client frei ändern kann, wie einer Query-String (z. B. ?tenantId=...), einem Request-Body-Feld oder einem Custom-Header.
Die Isolation-Grenzen, die du früh setzen solltest
Betrachte Tenant-Isolation als eine Reihe von Wänden, die du an mehreren Stellen bauen musst:
- Request-Grenze: Jede API-Anfrage löst serverseitig genau einmal einen Tenant auf
- Daten-Grenze: Jede Lese-/Schreiboperation ist für diesen Tenant scoped (nicht nur Lesungen)
- Speicher-Grenze: Dateien sind nach Tenant getrennt und der Zugriff wird serverseitig geprüft
- Job-Grenze: Hintergrundarbeit läuft mit einem expliziten Tenant-Kontext
- Analytics-Grenze: Events und Dashboards vermischen keine Tenants
Wenn du eine Tenant-Isolation-Checkliste erstellst, behandle jede Wand als verpflichtend. Eine fehlende ist genug für ein Leak.
Gemeinsame Tabellen vs. separate Datenbanken
Geteilte Tabellen (eine Datenbank, eine tenant_id-Spalte) sind schneller zu bauen und günstiger im Betrieb, benötigen aber strikte Schutzmaßnahmen wie durchgesetztes Scoping und Constraints. Separate Datenbanken (oder Schemas) reduzieren die Blast-Radius und erleichtern Compliance, bringen aber betrieblichen Mehraufwand (Migrationen, Reporting, Connection-Management).
Eine einfache Regel: Wenn du wenige, hochpreisige Tenants mit strengen Anforderungen erwartest, überlege stärkere physische Trennung. Erwartest du viele kleine Tenants, sind geteilte Tabellen üblich — aber nur, wenn du Scoping überall durchsetzt, nicht „an den meisten Stellen“.
Wo Daten am häufigsten leaken
Die meisten Tenant-Datenlecks in Prototypen sind keine „Hacker, die einbrechen“. Sie entstehen, wenn ein ehrlicher Fehler eine Single-Tenant-Annahme zu einem Multi-Tenant-Bug macht. Deshalb geht eine Tenant-Isolation-Checkliste weniger um ausgefallene Angriffe und mehr darum, Fußfallen zu entfernen.
Zuerst: Entscheide, was in deinem Produkt ein „Tenant“ ist (Org, Workspace, Account). Schreib es auf, setze es in Code-Kommentare und verwende überall dieselbe Bedeutung. Viele Lecks beginnen, wenn die UI „workspace“ verwendet, die API „org“ und die Datenbank „account_id“.
Die gängigsten Leak-Pfade sind unspektakulär, treten aber ständig auf:
- ID-Guessing und direkter Objektzugriff: ein Endpoint lädt
/invoices/123ohne zu prüfen, ob Invoice 123 zum Tenant des Aufrufers gehört. - Falsch scoped Queries: eine Abfrage filtert nach
user_id, vergisst abertenant_id, sodass Nutzer mit derselben E-Mail-Domain oder Rolle zusätzliche Zeilen sehen. - Geteilte Storage-Buckets oder -Ordner: Dateien werden unter vorhersehbaren Keys gespeichert und Access-Regeln beinhalten keinen Tenant-Kontext.
- Hintergrundjobs ohne Tenant-Kontext: ein Job führt „wöchentlichen Report senden“ für den falschen Tenant aus, weil die Queue-Payload kein
tenant_identhielt. - Admin- und Support-Shortcuts: „temporäre“ Endpunkte, Debug-Panels oder Exporte umgehen den normalen Autorisierungspfad.
Indirekte Lecks sind noch leichter zu übersehen, weil niemand Rohdaten „sieht“. Achte auf Features wie Suche, Autocomplete, Analytics-Dashboards und CSV-Exporte. Eine einzelne Zählung, ein Top-Ergebnis oder eine „Recent Items“-Liste kann verraten, dass ein anderer Tenant einen Kunden X oder ein Projekt mit Titel Y hat.
Wenn du ein KI-generiertes Prototyp geerbt hast, behandle jede Abfrage, jeden Job und jeden Storage-Zugriff als verdächtig, bis du eine klare Tenant-Grenzprüfung nachweisen kannst.
Wie du Isolation in deinen APIs durchsetzt (Schritt für Schritt)
Tenant-Isolation scheitert meist in APIs, weil Tenant-Kontext „manchmal“ statt „immer“ behandelt wird. Der sicherste Ansatz ist, Tenant-Kontext wie Authentifizierung zu behandeln: eine eindeutige Quelle der Wahrheit, angewendet auf jede Anfrage.
Ein wiederholbares API-Muster
Entscheide zuerst, wo der Tenant-Kontext autoritativ ist. Wähle genau eine Quelle: Token-Claims (häufig mit JWT) oder serverseitige Session. Alles andere ist nur Eingabe.
Dann implementiere einen einzigen Guard, der für jeden Endpoint läuft:
- Lese den authentifizierten Nutzer und den Tenant aus deiner gewählten Quelle der Wahrheit.
- Ignoriere jegliches
tenantId, das vom Client kommt (Body, Query-String, Headers). Wenn du es für Routing brauchst, behandel es als Hinweis und vergleiche es mit dem authentifizierten Tenant. - Führe eine konsistente Autorisierungsprüfung aus (Nutzer gehört zum Tenant, Rolle ist für die Aktion erlaubt).
- Übergib Tenant-Kontext in Service-Methoden, nicht nur in Controller. Vermeide „globale“ Helfer, die versehentlich ohne Tenant laufen können.
- Gib bei Tenant-Mismatch dieselbe Fehlerform zurück für „nicht gefunden“ und „nicht erlaubt“, wenn ein Unterschied Daten offenbaren könnte (zum Beispiel antworte so, als existiere der Datensatz nicht).
Ein konkretes Beispiel: Ein Endpoint wie GET /invoices/:id wirkt harmlos, aber wenn der Handler Invoice.findById(id) lädt, bevor er den Tenant prüft, kann man durch ID-Guessing Daten leaken. Die Lösung ist, die Abfrage zu scopen: „find invoice by id AND tenant“. Mach das gleiche bei Updates und Deletes.
Schneller Zwei-Tenant-Test
Während der Entwicklung halte zwei Test-Tenants offen in getrennten Browser-Profilen. Erstelle ähnliche Datensätze in beiden und versuche, IDs zwischen Tenants zu kopieren. Wenn etwas sichtbar wird, hat deine Tenant-Isolation-Checkliste gerade einen echten Fehler gefunden.
Wenn du ein KI-generiertes Prototyp geerbt hast, ist dies ein häufiger Fehler: Tenant-Kontext existiert, wird aber nicht konsistent über alle Endpunkte hinweg durchgesetzt.
Datenbank-Isolation: Abfragen, Constraints und Schutzmaßnahmen
Die meisten Tenant-Lecks passieren, weil die Datenbank eine Abfrage akzeptiert, die „richtig aussieht“, aber einen Filter vergessen hat. Wenn du eine praktische Tenant-Isolation-Checkliste willst, fange hier an: mache ungescoped Queries schwer, selbst aus Versehen.
Zuerst: Geh davon aus, dass jeder Lese-Pfad für Listen und Suche verwendet wird. Entwickler schreiben oft eine wiederverwendbare Abfrage und vergessen die Tenant-Bedingung. Eine gute Regel: Wenn eine Tabelle tenant-owned ist, muss jede Abfrage tenant_id einschließen, inklusive Zählungen, Exporte, Autocomplete und „recent items“.
Schutzmaßnahmen, die Fehler auffangen
App-Code-Prüfungen helfen, aber Datenbank-Regeln fangen Fehler, wenn sich Code ändert. Füge tenant_id zu jeder tenant-owned Tabelle hinzu und erzwinge es mit Constraints und Indexen. Zum Beispiel: nutze composite uniqueness wie (tenant_id, email) für Nutzer und stelle sicher, dass Foreign Keys Tenant-Scope einschließen (oder validiere Tenant-Match in Triggers, wenn composite FKs nicht praktikabel sind).
Schnelle Guardrails, die du früh hinzufügen solltest:
- Setze
NOT NULL tenant_idauf tenant-owned Tabellen. - Nutze Composite-Indexes, die mit
tenant_idbeginnen, um scoped Queries schnell zu machen. - Verwende Composite-Unique-Constraints, um Cross-Tenant-Kollisionen zu vermeiden.
- Blockiere „default tenant“-Fallbacks in Production.
Row-Level-Security (RLS) und „globale“ Tabellen
Row-Level-Security kann helfen, wenn mehrere Services oder Query-Pfade dieselben Tabellen berühren. Es funktioniert am besten, wenn jede Verbindung einen Tenant-Kontext setzt und du es zuverlässig testen kannst. Es ersetzt nicht gute Autorisierung, reduziert aber die Blast-Radius, wenn jemand einen Filter vergisst.
Für „globale“ Tabellen wie Pläne oder Templates: trenne wirklich globale Daten von Tenant-Overrides. Ein gängiges sicheres Muster ist: globale Zeilen haben keine tenant_id, Tenant-Anpassungen leben in einer separaten tenant-owned Tabelle.
Plane schließlich Admin-Support-Zugriffe. Nutze eine separate Rolle oder einen separaten Endpoint, erfordere explizite Tenant-Auswahl und logge jeden Admin-Lese- und Schreibzugriff mit wer, wann und welchem Tenant. Wenn du ein KI-generiertes Schema geerbt hast, in dem das unordentlich ist, kann FixMyMess Abfragen und Constraints schnell auditieren und zeigen, wo Isolation brechen kann.
Dateien und Objekt-Speicher: Vermeide versehentlichen Cross-Tenant-Zugriff
Dateien sind ein häufiger Ort für Leaks in Prototypen. Code „funktioniert“ oft mit einem einzigen Bucket und einem Ordner und bricht dann stillschweigend die Isolation, wenn ein zweiter Tenant eine Datei mit demselben Namen hochlädt oder wenn eine geteilte URL weitergeleitet wird.
Beginne mit einer Regel: Jedes gespeicherte Objekt braucht eine eindeutige Tenant-Grenze. Das einfachste Muster ist ein Pflicht-Tenant-Prefix im Storage-Key (z. B. tenants/<tenant_id>/...) und die App lehnt das Lesen oder Schreiben von allem ab, das nicht zum aktuellen Tenant passt.
Vermeide öffentliche Buckets und langlebige Public-URLs per Default. Wenn du Sharing brauchst, bevorzuge kurzlebige signierte URLs, die nur erzeugt werden, nachdem dein Server Identität und Tenant-Zugehörigkeit verifiziert hat. Vertraue niemals auf einen client-provided Datei-Pfad oder Objekt-Key.
Deine Download- und Preview-Endpunkte sind die eigentlichen Gatekeeper. Ein häufiger Bug: GET /files/:id lädt einen DB-Record per id und gibt dann die Datei zurück, aber die Abfrage vergisst WHERE tenant_id = ?. Ein fehlender Filter wird schnell zu einem Cross-Tenant-Breach. Behandle das als Teil deiner Tenant-Isolation-Checkliste.
Achte auch auf Metadaten. Dateinamen, EXIF-Daten, PDF-Eigenschaften oder uploaded_by-Strings können Tenant-Namen, interne IDs oder E-Mail-Adressen offenbaren, wenn Dateien geteilt werden.
Ein schneller Audit, den du heute laufen lassen kannst:
- Bestätige, dass jeder Objekt-Key ein Tenant-Prefix enthält und serverseitig durchgesetzt wird.
- Prüfe, dass jede Dateisuche
tenant_idin der Abfrage und in der Autorisierung enthält. - Stelle sicher, dass geteilte Zugriffe kurzlebige signierte URLs nutzen, keine öffentlichen Objekte.
- Entferne oder schreibe sensible Metadaten beim Upload um (insbesondere Bilder und PDFs).
- Definiere tenant-spezifische Aufbewahrungs- und Löschregeln und verifiziere vollständige Löschung beim Offboarding.
Wenn du ein KI-generiertes Prototyp geerbt hast (Lovable/Bolt/v0/Cursor/Replit), findet FixMyMess häufig Storage-Regeln, die im Code richtig aussehen, aber in Produktion nicht konsistent durchgesetzt werden.
Hintergrundjobs und Queues: Tenant-Kontext erhalten
Hintergrundarbeit ist der Ort, an dem Tenant-Isolation stillschweigend bricht. Die API-Anfrage hatte die Tenant-ID und die richtigen Berechtigungen, aber sobald Arbeit an eine Queue übergeben wird, kann dieser Kontext verschwinden. Dann holt sich ein Worker einen Job, läuft mit „System“-Zugriff und greift die Daten des falschen Tenants an.
Eine einfache Regel hilft: Jeder Job muss seinen Tenant-Kontext in der Payload beim Erstellen tragen. Das heißt in der Regel tenant_id plus die minimal benötigten Identifikatoren (z. B. user_id oder invoice_id) und nichts, das „später nachgeschlagen“ werden müsste, ohne Prüfungen.
Verlasse dich nie auf „aktueller Nutzer“ im Worker. Worker haben keinen echten eingeloggten Nutzer, und jede geteilte globale State (wie ein gecachtes User-Objekt oder default DB-Schema) kann auf den zuletzt laufenden Job verweisen. Stattdessen sollte der Worker am Start des Jobs explizit den Tenant-Scope setzen und ihn validieren, bevor er irgendetwas tut.
Retries können auch Leaks verursachen. Wenn ein Job fehlschlägt und erneut ausgeführt wird, stelle sicher, dass die Retry-Payload weiterhin die Tenant-ID enthält und der Worker bei jedem Versuch Tenant-Scoping erneut anwendet. Das gleiche gilt für Dead-Letter-Queues: Beim Inspizieren oder Replayen fehlgeschlagener Jobs muss der Tenant-Kontext weiterhin vorhanden und sichtbar sein.
Geteilte Queues sind in Ordnung, aber gemischte Tenant-Logs sind riskant. Wenn dein Worker Request-Bodies, SQL-Errors oder komplette Objekt-Dumps loggt, kannst du versehentlich die Daten eines Tenants in Logs schreiben, die andere Mitarbeiter (oder Tools) sehen können. Logge mit Tenant-IDs und kurzen Identifikatoren, nicht mit kompletten Datensätzen.
Schnelle Checks, die die meisten Probleme aufdecken:
- Erstelle einen Job und bestätige, dass
tenant_idin der Job-Payload gespeichert ist und in Worker-Logs angezeigt wird. - Lass den Worker sofort fehlschlagen, wenn
tenant_idfehlt oder nicht mit dem geladenen Datensatz übereinstimmt. - Verifiziere, dass bei Retry und Dead-Letter-Handling Tenant-Scoping erneut angewendet wird und nicht „erinnert“ wird.
- Füge per-Tenant Rate-Limits oder Queue-Fairness hinzu, damit ein lauter Tenant andere nicht ausbremst.
Wenn du ein KI-generiertes Prototyp geerbt hast, sind Worker oft der Ort, an dem Tenant-Kontext implizit und unsicher ist. FixMyMess kann Queue- und Worker-Pfade auditieren und Isolation-Probleme schnell beheben, bevor sie zu einem Datenvorfall werden.
Caching, Sessions und Notifications: Versteckte Cross-Tenant-Risiken
Caching und Sessions werden in Prototypen leicht „gesetzt und vergessen“. Deshalb sind sie ein häufiger Grund, warum eine Tenant-Isolation-Checkliste im echten Leben versagt. Die Anfrage eines Tenants füllt den Cache, der nächste Tenant bekommt dieselbe Antwort.
Ein einfaches Beispiel: Deine API liefert /settings für den aktuellen Nutzer. Du cachest es unter settings für 5 Minuten. Tenant A ruft es zuerst ab, dann sieht Tenant B das Logo, den Plan oder sogar die Billing-E-Mail von Tenant A. Niemand hat dich „gehackt“ — es war nur ein tenant-blinder Cache-Key.
Cache-Keys, Invalidation und „geteilte“ Objekte
Lass die Cache-Identität mit der Daten-Identität übereinstimmen. Wenn die Daten tenant-gescoped sind, muss der Cache das auch sein, inklusive Invalidation.
- Füge
tenant_id(und oft Nutzerrolle) in Cache-Keys für API-Antworten ein. - Invalidiere pro Tenant, wenn Tenant-Daten sich ändern, nicht nur pro Endpoint.
- Sei vorsichtig mit „globalen“ Caches (Feature-Flags, Templates), die heimlich tenant-spezifische Felder enthalten.
- Bevorzuge das Cachen von IDs und erneute Zugriffsprüfungen beim Lesen, wenn Daten sensibel sind.
Sessions, Notifications und Logs
Sessions können auch Grenzen überschreiten, wenn du sie nicht eng bindest. Ein Session-Token sollte auf einen Nutzer und einen Tenant verweisen, und jede Anfrage sollte beides bestätigen.
Vor dem Launch solltest du diese Bereiche stichprobenartig prüfen:
- Session-Storage verhindert Replay über Tenants hinweg (Token -> user_id + tenant_id, serverseitig verifiziert).
- Passwort-Resets, Einladungen und Magic Links enthalten Tenant-Kontext und laufen schnell ab.
- E-Mail-, SMS- und In-App-Notifications prüfen beim Senden, dass der Empfänger zum Tenant gehört.
- Logs speichern niemals Geheimnisse (API-Keys, Tokens) oder sensible Tenant-Daten „zur Fehlersuche".
Wenn du ein KI-generiertes Prototyp geerbt hast, verstecken sich diese Probleme oft in Glue-Code. FixMyMess kann ein schnelles Audit durchführen, tenant-blinde Caches, schwache Sessions und unsichere Notification-Pfade finden, bevor sie in Produktion gehen.
Beispiel: ein einfaches Tenant-Datenleck und wie es entsteht
Eine kleine Agentur und eine lokale Bäckerei melden sich in demselben SaaS-Prototyp an. Beide legen „Kunden“ im Tool an und nutzen eine einfache Listen-Seite, um sie zu finden.
Der Prototyp speichert Datensätze wie clients(id, tenant_id, name, email). Der API-Endpoint wirkt harmlos: GET /api/clients?search=ann.
Der Bug: Die Abfrage filtert nach dem Suchbegriff, vergisst aber den Tenant.
Also sucht die Agentur nach „Ann“ und bekommt auch die „Ann Smith“ der Bäckerei zurück. Zuerst bemerkt niemand etwas, weil es nur auftritt, wenn Namen übereinstimmen.
Es wird schlimmer: dieselbe Abfrage wird für einen CSV-Export wiederverwendet und enthält Cross-Tenant-Zeilen. Ein Hintergrundjob, der „wöchentliche Kundenübersicht“ sendet, verwendet dieselbe Logik und hängt die falschen Datensätze an. Ein Dashboard-Widget zählt „neue Kunden diese Woche“ über alle Tenants hinweg, sodass die Bäckerei aufgeblähte Zahlen sieht und die Agentur einen unerklärlichen Rückgang.
Ein schneller Fix ist, diesen einen Endpoint mit einem Tenant-Filter zu versehen. Das stoppt das unmittelbare Leak, ist aber fragil, weil der nächste Endpoint denselben Fehler wiederholen könnte.
Eine richtige Lösung hat in der Regel zwei Schichten:
- Mache Tenant-Scope automatisch in der API (leite
tenant_idvom authentifizierten Nutzer ab, nicht aus Request-Parametern). - Füge Datenbank-Guardrails hinzu (RLS oder eine Pflicht-Tenant-Constraint, sodass ungetimte Queries fehlschlagen).
- Stelle sicher, dass Exporte, E-Mails und Analytics-Abfragen denselben gescopten Zugriffsweg nutzen.
Um Regressions zu verhindern, behalte einen wiederholbaren Test: Erstelle zwei Tenants, füge in beiden denselben Namen ein, rufe die Listen-API als Tenant A auf und assert, dass jede zurückgegebene Zeile Tenant A's tenant_id hat. Führe das für API und Export-Job aus.
Wenn du ein KI-generiertes Prototyp geerbt hast, ist dieses Muster sehr verbreitet. Teams wie FixMyMess finden oft das Leck in einem Endpoint und verfolgen es dann zu gemeinsamen Query-Helpern und Hintergrundjobs, sodass es einmalig und dauerhaft behoben wird.
Audit-Checkliste: Schnelle Prüfungen im gesamten Stack
Eine Tenant-Isolation-Checkliste ist am nützlichsten, wenn sie dich zwingt, denselben Fehler an verschiedenen Stellen zu suchen: „tenant id fehlt oder wird ignoriert“. Führe dieses Audit immer dann durch, wenn du ein neues Feature, einen neuen Endpoint oder eine neue Hintergrundaufgabe hinzufügst.
Beginne mit diesen schnellen Prüfungen:
- APIs: Der Tenant muss serverseitig abgeleitet werden (aus der Nutzersession, dem Token oder Subdomain), nicht vom Client als vertrauenswürdiges Feld. Jede Route, die Daten liest oder schreibt, sollte Tenant-Scoping erzwingen, inklusive „admin“ und interner Endpunkte.
- Datenbank: Jede tenant-owned Tabelle hat einen Tenant-Key, und man kann keine Zeile ohne ihn einfügen. Abfragen sind immer nach Tenant gescoped und es gibt Guardrails (Constraints, Policies oder Tests), die laut fehlschlagen, wenn Scope fehlt.
- Dateien und Objekt-Speicher: Pfade sind pro Tenant (z. B. Tenant-Prefix), Zugriff ist signiert oder anderweitig gesichert, und „public by default“ ist aus. Verlasse dich nicht darauf, dass die UI andere Tenants Dateien versteckt.
- Hintergrundjobs: Jobs tragen Tenant-Kontext explizit, validieren ihn vor Arbeitsbeginn und loggen sicher (keine Geheimnisse, keine rohen Kundendaten). Retries dürfen keinen Tenant-Kontext verlieren.
- Analytics und Exporte: Events enthalten Tenant-IDs, Dashboards sind nach Tenant gefiltert und Exporte (CSV, E-Mails, „Download All") dürfen keine anderen Tenants enthalten.
10-Minuten Smoke-Test
Erstelle zwei Tenants: „Acme“ und „Beta“. Erstelle jeweils einen Datensatz (einen Nutzer, eine Rechnung, eine Datei und ein Analytics-Event). Führe dann einfache Tests durch: ändere eine ID in einer URL, spiele einen API-Aufruf erneut ab, während du im anderen Tenant eingeloggt bist, oder starte einen Export aus jedem Tenant.
Wenn du auch nur eine Cross-Tenant-Leseoperation findest, behandle das als Produktions-Blocker. Teams bitten FixMyMess oft um ein schnelles Isolation-Audit für KI-generierte Prototypen, weil diese Lücken in kopiertem Code, Job-Handlern und „temporären“ Admin-Screens versteckt sind.
Häufige Multi-Tenant-Fallen, die du vermeiden solltest
Die meisten Tenant-Lecks entstehen nicht durch einen großen Fehler, sondern durch kleine Abkürzungen, die in einem Prototyp harmlos wirken und dann stillschweigend in Produktion gelangen.
Fallen, die echte Lecks verursachen
Achte in deiner Tenant-Isolation-Checkliste auf folgende Muster:
- Akzeptieren eines
tenantIdaus der UI, dem Query-String oder Request-Body und Verwenden in Abfragen. Der Server sollte Tenant-Kontext vom authentifizierten Nutzer oder Token ableiten, nicht aus Nutzereingaben. - Haupt-CRUD-Endpunkte sichern, aber „Seitent“ Routes wie Suche, Count, Export, Autocomplete und Webhook-Handler vergessen. Diese fragen oft breitere Tabellen ab und werden leicht in Reviews übersehen.
- Einen geteilten „admin“-Endpoint behalten und annehmen, er sei sicher, weil er nicht in der UI ist. Ohne strikte Rollenprüfungen und klaren erlaubten Tenant-Scope wird er zur Universal-Backdoor.
- Caching für Listendpunkte ohne tenant-aware Cache-Key nutzen. Eine gecachte Antwort kann vielen Tenants serviert werden, besonders bei Pagination und Filtern.
- Analytics Tenants vermischen und Dashboards als Wahrheit behandeln. Sobald gemischte Daten in Reports sind, treffen Leute Entscheidungen darauf basierend und einer Aufräumaktion ist schwer.
Ein einfaches Beispiel: Deine API scopt /invoices korrekt nach Tenant, aber /invoices/export prüft nur „ist eingeloggt“ und läuft eine breite Query. Ein Kunde klickt auf Export und erhält Reihen anderer Firmen.
Wenn du ein KI-generiertes Prototyp geerbt hast, treten diese Probleme oft auf, weil Code dupliziert ist und „fast gleich“ über Routen hinweg. FixMyMess sieht häufig einen Endpoint aktualisiert mit Tenant-Scoping, während drei ähnliche Endpunkte noch Daten leaken.
Eine gute Regel: Jede Anfrage, jede Abfrage, jeder Cache-Eintrag und jedes Event sollte explizit Tenant-Kontext tragen und geschlossen fehlschlagen, wenn er fehlt.
Nächste Schritte: Isolation härten bevor du in Produktion gehst
Bevor du echte Kunden an Bord holst, entscheide, wie du Isolation beheben willst: den vorhandenen Prototyp patchen oder nur die riskanten Teile neu bauen (Auth, Data Access Layer, Background Jobs). Patchen ist schneller, wenn die Architektur größtenteils sinnvoll ist. Neuaufbau ist sicherer, wenn Tenant-Prüfungen im Code verstreut sind oder wenn die App „wer der Nutzer ist“ mit „welchem Tenant er angehört“ vermischt.
Ein praktischer Weg ist, Isolation als Release-Blocker zu behandeln und einen kleinen Regressionsplan hinzuzufügen, den du bei jeder Änderung sensitiver Bereiche ausführst. Selbst ein einfacher „Zwei-Tenant-Test-Suite“ fängt die meisten Lecks.
Ein einfacher 1-Stunden-Härtungsplan
Arbeite diese Schritte in Reihenfolge ab:
- Wähle zwei Test-Tenants (Tenant A und Tenant B) und erstelle identische Daten in beiden.
- Führe deine Kern-Flows aus, während du in Tenant A eingeloggt bist, und versuche, Tenant B durch Ändern von IDs in URL, Request-Body und Filtern zu erreichen.
- Trigger Hintergrundjobs (E-Mails, Exporte, Webhooks) und bestätige, dass sie nur den korrekten Tenant betreffen.
- Prüfe Object-Storage-Keys und signierte URLs, um sicherzustellen, dass sie tenant-gescoped sind.
- Verifiziere, dass Analytics-Events Tenant-Kontext enthalten und standardmäßig nicht über Tenants hinweg abfragbar sind.
Plane ein kurzes Isolation-Audit kurz vor dem Launch. Ziel ist nicht Perfektion, sondern Vertrauen, dass deine höchsten Risiko-Pfade abgedeckt sind und dass deine Checkliste tatsächlich vom Code durchgesetzt wird, nicht nur durch Konventionen.
Wenn dein Prototyp von Tools wie Lovable, Bolt, v0, Cursor oder Replit generiert wurde, geh davon aus, dass Tenant-Grenzen nicht sorgfältig entworfen wurden. FixMyMess kann ein kostenloses Code-Audit durchführen, um aufzuzeigen, wo Tenant-Kontext verloren geht, und dann Auth, Data Access und Deployment-Readiness härten, damit deine ersten echten Kunden nicht zu deiner Test-Suite werden.