Zum Inhalt springen
DedicatedPHP Kontakt

Mandantenfähige Datenisolation in PHP ohne Datenlecks

Entwerfen Sie ein PHP-SaaS, das organisationsübergreifende Zugriffe mit explizitem Kontext sowie Kontrollen für Daten, Queues, Cache und Tests verhindert.

Redaktionelles Diagramm eines PHP-SaaS mit isolierten Organisationen in Datenbank, Cache, Dateien und Queues

Mandantenfähige Datenisolation in PHP lässt sich nicht dadurch lösen, dass auf dem Hauptbildschirm eine Bedingung WHERE organization_id = ? hinzugefügt wird. Ein Datenleck kann über eine API, einen Export, einen Cache, einen Anhang, einen Queue-Consumer oder einen geplanten Prozess entstehen. Es kann auch auftreten, wenn ein legitimer Administrator die Organisation wechselt und das System einen vorherigen Kontext beibehält.

Das architektonische Ziel muss klar sein: Keine Operation, die Kundeninformationen liest, ändert, verarbeitet oder bereitstellt, darf ohne einen überprüfbaren Organisationskontext ausgeführt werden können. Dieser Kontext muss explizit weitergegeben und an jeder relevanten Grenze der Anwendung validiert werden.

Was eine SaaS-Anwendung isolieren muss

Was eine SaaS-Anwendung isolieren muss — guía visual de DedicatedPHP

Das Modell der Transaktionsdaten ist nur ein Teil der Risikofläche. Erfassen Sie die Ressourcen, die einen organisatorischen Eigentümer haben, und definieren Sie für jede Ressource, wie ihre Zugehörigkeit identifiziert, gespeichert, abgerufen, gelöscht und auditiert wird.

  • Transaktionsdaten: Benutzer, Projekte, Bestellungen, Rechnungen, Konfigurationen und Beziehungen zwischen Entitäten.
  • Dateien und Anhänge: Objekte in externem Speicher, Vorschaubilder, generierte Dokumente und ihre Metadaten.
  • Cache: Abfrageergebnisse, berechnete Berechtigungen, Sitzungen, API-Antworten und Konfigurationsdaten.
  • Suchindizes: Indexierte Dokumente, Vorschläge und zuvor aggregierte Filter.
  • Asynchrone Verarbeitung: Queue-Jobs, Wiederholungsversuche, Import-Batches und Benachrichtigungen.
  • Betrieb und Überwachung: Protokolle, Ablaufverfolgungen, Metriken, Support-Exporte und interne Werkzeuge.

Nicht alle Ressourcen erfordern dieselbe Strategie. Ein öffentlicher Katalog kann gemeinsam genutzt werden, während eine Rechnung, ihr PDF und die Download-Protokolle die eindeutige Verknüpfung mit der Organisation bewahren müssen. Die Entscheidung muss dokumentiert werden, damit eine neue Entität nicht ohne Eigentumsregeln entsteht.

Das Modell zur Datenisolation auswählen

Es gibt drei gängige Modelle. Keines ist universell überlegen: Die Wahl hängt von regulatorischen Anforderungen, Volumen, Betrieb, Geschäftsmodell und der Fähigkeit des Teams ab, die Plattform zu betreiben.

Gemeinsame Datenbank mit Organisationsschlüssel

Alle Organisationen teilen Tabellen, und jeder der Isolation unterliegende Datensatz enthält einen Schlüssel wie organization_id. Dies ist der direkteste Ansatz, um das Produkt weiterzuentwickeln und globale aggregierte Abfragen auszuführen. Im Gegenzug erfordert er äußerste Disziplin: Jede Abfrage, Beziehung, jeder Index, Cache und Job muss den Organisationskontext einhalten.

Verwenden Sie mindestens Fremdschlüssel, sofern angebracht, zusammengesetzte Indizes, die mit organization_id beginnen, sowie ebenfalls zusammengesetzte Eindeutigkeitsbeschränkungen. Beispielsweise darf ein innerhalb einer Organisation eindeutiger Bestellcode nicht global als eindeutig definiert werden, wenn dies nicht die Geschäftsregel ist.

Getrenntes Schema pro Organisation

Jeder Kunde arbeitet in einem eigenen logischen Schema innerhalb desselben Datenbankservers. Dies reduziert das Risiko, einen Filter in getrennten Tabellen zu vergessen, erschwert jedoch Migrationen, Verbindungen, Analysetools und globale Abfragen. Es ist nur geeignet, wenn Datenbank-Engine, Framework und täglicher Betrieb dieses Muster konsistent unterstützen.

Datenbank pro Organisation

Getrennte Datenbanken bieten eine stärkere Grenze und können Wiederherstellungen oder Umzüge einzelner Kunden erleichtern. Sie erhöhen jedoch auch den Bestand an Verbindungen, Migrationen, Sicherungskopien, Überwachung und Bereitstellungen von Strukturänderungen. Besonders zu bewerten ist, wie globale Berichte, Massenänderungen und die Fehlerwiederherstellung ausgeführt werden.

Die physische Trennung reduziert bestimmte Fehlerklassen, ersetzt jedoch weder Autorisierung, Dateikontrolle, Geheimnisverwaltung noch die Validierung des Kontexts in gemeinsam genutzten Diensten.

Referenzarchitektur: expliziter Kontext an den Grenzen

Der Organisationskontext darf nicht aus beliebigen Parametern abgeleitet werden, die vom Browser gesendet werden. Er muss aus einer authentifizierten und autorisierten Quelle aufgelöst werden: einer validierten Subdomain, einem Token mit geeigneter Audience, einer Benutzerzugehörigkeit oder Zugangsdaten für eine Integration, die einer einzigen Organisation zugeordnet sind.

In einer PHP-Anwendung kann eine Eingangsschicht ein unveränderliches Kontextobjekt mit der Organisationskennung, dem Akteur, seinen Berechtigungen und einer Anfragekennung erstellen. Controller, Konsolenbefehle und Queue-Consumer erhalten diesen Kontext oder rekonstruieren ihn anhand verifizierter Daten. Vermeiden Sie veränderliche globale Variablen, die in lang laufenden Prozessen möglicherweise unbeabsichtigt weiterbestehen.

final class OrganizationContext {
    public function __construct(
        public readonly string $organizationId,
        public readonly string $actorId
    ) {}
}

Repositories müssen den Kontext verlangen, um isolierte Entitäten abzufragen oder zu ändern. Eine Schnittstelle, die ein Auslassen erschwert, ist einer impliziten Konvention vorzuziehen, die vom Gedächtnis jedes Entwicklers abhängt. Wenden Sie, wo möglich, zusätzlich Zugriffsrichtlinien in der Domänenschicht an: Die Zugehörigkeit zu einer Organisation autorisiert nicht automatisch jede Aktion innerhalb dieser Organisation.

Vergessene Filter in Abfragen und Beziehungen vermeiden

Eine isolierte Abfrage muss nach Organisation filtern, bevor sie nach Geschäftskennungen sucht. Zuerst einen Datensatz über id abzurufen und seinen Eigentümer erst danach zu prüfen, kann zu Offenlegungen führen, wenn das Ergebnis serialisiert, protokolliert oder verwendet wird, bevor es abgelehnt wird.

  • Zentralisieren Sie Abfragen in Repositories oder Lese-Services mit Methoden, die den Kontext entgegennehmen.
  • Verbieten Sie direkten Zugriff auf isolierte Modelle aus Controllern, Templates und Event-Consumern.
  • Prüfen Sie Beziehungen: Eine verzögert geladene Beziehung kann den auf die Hauptentität angewendeten Filter umgehen.
  • Nutzen Sie Datenbankbeschränkungen, um Beziehungen zwischen Zeilen unterschiedlicher Organisationen zu verhindern, wenn das Modell dies zulässt.
  • Definieren Sie Konventionen für Migrationen, Testdaten und analytische Abfragen.

In Datenbank-Engines, die Row-Level-Security-Richtlinien anbieten, können diese eine zusätzliche Schutzmaßnahme bieten. Ihre Einführung muss jedoch Verbindungstests, Rollenverwaltung und die Überprüfung administrativer Prozesse einschließen. Es sollte nicht angenommen werden, dass eine Datenbankrichtlinie automatisch Dateien, Cache oder externe Indizes schützt.

Risiken außerhalb des Haupt-Webablaufs

Undurchsichtige Kennungen reduzieren die Enumeration, autorisieren jedoch keinen Zugriff. Eine UUID oder eine zufällige Kennung muss weiterhin innerhalb der aktiven Organisation aufgelöst werden. Ebenso benötigt eine signierte Download-URL ein Objekt, das zum richtigen Organisationskontext gehört, eine angemessene Ablaufzeit und Regeln für den Widerruf bei Berechtigungsänderungen.

Cache-Schlüssel müssen die Organisationskennung enthalten und, wenn der Inhalt von Berechtigungen abhängt, eine zusätzliche Rollen- oder Autorisierungsversionsdimension. Ein Schlüssel wie dashboard:summary ist in einer mandantenfähigen Umgebung unsicher; ein Schlüssel mit explizitem Organisationskontext ermöglicht zudem präzisere Invalidierungen.

Exporte sind besonders sensibel, weil sie häufig außerhalb der ursprünglichen Anfrage ausgeführt werden. Speichern Sie, wer ihn angefordert hat, für welche Organisation, welche Filter genehmigt wurden und wo das Ergebnis bereitgestellt wird. Senden Sie keine Anhänge oder Links an Empfänger, die aus nicht validierten Daten berechnet wurden.

Den Kontext in APIs, Webhooks und Queues weitergeben

Eine API muss die Organisation aus den Zugangsdaten ableiten oder prüfen, dass die angeforderte Ressource zu der mit diesen Zugangsdaten verknüpften Organisation gehört. Einen Header X-Organization-Id zu erlauben, kann für Operatoren mit expliziter Delegation gültig sein, erfordert jedoch spezifische Autorisierung, Auditierung und eine Schnittstelle, die den Wechsel des Organisationskontexts sichtbar macht.

Eingehende Webhooks dürfen einer im Body enthaltenen Organisationskennung nicht vertrauen, ohne Signatur, Absender und vorherige Zuordnung der Integration zu prüfen. Erzeugen Sie für ausgehende Webhooks Ereignisse aus bereits abgegrenzten Daten und vermeiden Sie, Nutzdaten aus einer gemeinsamen Queue ohne Validierung des Empfängers wiederzuverwenden.

Jeder asynchrone Job muss neben der Ressourcenkennung eine Organisationskennung transportieren und den Kontext vor der Abfrage rekonstruieren. Der Consumer muss beide Werte prüfen, auch wenn der Job intern erstellt wurde. Wiederholungsversuche, verzögerte Jobs und geplante Aufgaben benötigen dieselbe Regel: Es gibt keinen impliziten Anfragekontext, der sicher verfügbar ist.

Überprüfbare Tests und Diagnosesignale

Der wichtigste Test ist nicht, dass eine Organisation ihre eigenen Daten sieht, sondern dass sie die Daten einer anderen weder lesen noch ändern kann. Erstellen Sie zwei Organisationen mit absichtlich ähnlichen Daten und führen Sie Integrationstests gegen jeden Einstiegspunkt aus: Weboberfläche, API, Befehle, Exporte, Downloads und Queue-Consumer.

  • Fordern Sie eine Ressource der Organisation B mit einer Sitzung oder Zugangsdaten der Organisation A an und erwarten Sie eine Antwort, die keine Informationen preisgibt.
  • Versuchen Sie, organisationsübergreifende Ressourcen zu aktualisieren, zu löschen, herunterzuladen und zu exportieren, nicht nur abzufragen.
  • Prüfen Sie, dass die Cache-Schlüssel von A und B unabhängige Ergebnisse erzeugen.
  • Führen Sie einen Queue-Job mit einer Ressource einer anderen Organisation aus und prüfen Sie, dass er kontrolliert fehlschlägt.
  • Testen Sie Wiederherstellungen, Importe und nächtliche Aufgaben mit Daten von mehr als einer Organisation.
  • Protokollieren Sie sensible Aktionen mit Akteur, Organisation, Ressource und Ergebnis, ohne unnötige personenbezogene Daten in die Protokolle aufzunehmen.

Eigenschaftsbasierte Tests können die manuellen Fälle ergänzen: Für jede unter einer Organisation erstellte Ressource sollte kein Akteur ohne gültige Zugehörigkeit sie über einen öffentlich erreichbaren Pfad beobachten oder verändern können. Diese Eigenschaft muss auf zukünftige Änderungen an Endpunkten und Repositories angewendet werden.

Einführungsplan für eine bestehende Anwendung

Wenn die Daten bereits vermischt sind, beginnen Sie nicht mit der Neuschreibung der gesamten Anwendung. Erfassen Sie zuerst Entitäten, Abläufe, Integrationen und administrative Zugriffe. Definieren Sie anschließend das Eigentum jedes Datensatzes und klären Sie mehrdeutige Fälle mit überprüfbaren Geschäftsregeln.

  1. Fügen Sie die Organisationsentität und den Zugehörigkeitsschlüssel zu den Zieltabellen hinzu.
  2. Befüllen Sie diesen Schlüssel durch eine kontrollierte Migration und bewahren Sie Nachweise für Fälle ohne zuverlässige Zuordnung auf.
  3. Führen Sie abgegrenzte Repositories und Tests für organisationsübergreifenden Zugriff in den sensibelsten Pfaden ein.
  4. Nehmen Sie den Organisationskontext in neue Cache-Einträge, Dateien, Suchen und Jobs auf.
  5. Migrieren Sie schrittweise die alten Abläufe und blockieren Sie neue Abfragen ohne Kontext in der Codeüberprüfung.
  6. Aktivieren Sie strengere Kontrollen, wenn Metriken und Tests ausreichende Abdeckung belegen.

Entscheidungen, die vor dem Wachstum dokumentiert werden sollten

Entscheidungen, die vor dem Wachstum dokumentiert werden sollten — guía visual de DedicatedPHP

Bevor Sie die nächste Organisation aufnehmen, dokumentieren Sie das gewählte Modell, die Quelle der Wahrheit für den Kontext, Ausnahmen für administrative Zugriffe, die Kennungsstrategie, Cache-Grenzen, Dateieigentum, Datenwiederherstellung, Protokollaufbewahrung und das Verfahren bei Verdacht auf organisationsübergreifenden Zugriff.

Legen Sie außerdem fest, wer im Namen einer anderen Organisation handeln darf, wie diese Delegation genehmigt und wie sie widerrufen wird. Mandantenfähige Datenisolation in PHP wird durch explizite Entscheidungen, wiederholbare technische Einschränkungen und Tests aufrechterhalten, die ein Architekturversprechen in überprüfbares Verhalten verwandeln.

Möchten Sie diese Ideen in Ihrem Projekt anwenden?Lass uns über deine PHP-Plattform sprechen.
Verwandten Dienst anzeigen