2016-08-02 7 views
-1

Wir entwickeln mandantenfähige Angular Web App, die Azure DocumentDb als Speicher verwendet. Dokumente aus allen Mandanten der App, die in der gleichen Sammlung gespeichert sind und durch das Attribut mandantId des Dokuments unterschieden werden. Wir werden einen .NET-Dienst der mittleren Ebene haben, der den Hauptschlüssel für DocumentDb enthält und REST-API-Endpunkte für CRUD-Vorgänge durch Web App verfügbar macht. Benutzer der Web App werden von oAuth-Anbietern (Google, Facebook, Microsoft) authentifiziert. Was ist die beste Vorgehensweise zum Sichern von Tenant-Daten, sodass Benutzer eines Mandanten nicht auf Daten von anderen Tenants zugreifen können?Sicherung des Zugriffs auf DocumentDB von Multitenant SPA

+0

Leider ist diese Art von Frage off-topic für StackOverflow, da es keine einzige "Best Practice" Möglichkeit gibt, dies zu erreichen. Dies ist eine ziemlich breite und meinungsfordernde Frage mit möglicherweise vielen Antworten. –

Antwort

1

Ich bin nicht sicher genug, um es am besten Praxis zu nennen, aber wir haben eine mittlere Schicht REST-API, wie Sie tun, und hier ist das, was wir tun:

  1. Clients (auch Browser-Code) können beliebige Abfragen einreichen . Wir verwenden sql-from-mongo, also sind diese in mongoähnlicher Syntax, die für JavaScript-Clients einfacher ist, eine Abfrage zu erstellen, aber was ich vorschlage, wäre genauso sicher mit Raw-SQL-Abfragen, solange Sie die Variablen parametrieren und nicht zulassen irgendwelche Projektionen in Ihrer SELECT Klausel. Dieser letzte Teil erreichen wir in der sql-from-mongo Übersetzung, aber Sie könnten die Projektionen entfernen (ersetzen Sie die zur Verfügung gestellte SELECT Klausel mit SELECT *) oder jede Abfrage ablehnen, die nicht mit SELECT * gestartet wurde. Dies ist kritisch, denn ohne sie könnten schlechte Schauspieler ihre eigenen tenentID oder userID projizieren, dass der Rest dieser Steuerelemente aus.

  2. Unsere REST-Middleware speichert den Mandanten- und Benutzerkontext für jeden Client und enthält unsere Autorisierungsspezifikation (ähnlich wie Firebase). In der einfachsten Form ist der Benutzer an ein einzelnes Tenent gebunden und dieser Benutzer hat Leseberechtigung für alle Daten für diesen Mandanten, aber Sie können alles angeben.

  3. Wenn die Abfrage ausgeführt wird, wird das zurückgegebene Dataset mit der Autorisierungsspezifikation verglichen. Je nach Situation werden Anfragen mit beliebig vielen nicht erlaubten Dokumenten entweder komplett abgelehnt oder die nicht erlaubten Dokumente werden aus der von uns zurückgegebenen Ergebnismenge herausgefiltert.

  4. Auf der Schreibseite der Dinge machen wir etwas ähnliches. Wir prüfen das Update anhand der Autorisierungsspezifikation und lehnen alle ab, die nicht entsprechen. Es ist ein bisschen komplizierter als das, weil wir einen Sproc für alle Schreibvorgänge verwenden und wir eine mongoähnliche Syntax für In-Place-Updates haben, und wir implementieren Cross-Document-ACID für alle Schreibvorgänge (mit dem Sproc), aber Sie können was ich ohne all das vorschlage.

Hoffe, das hilft. Fühlen Sie sich frei, Fragen in den Kommentaren zu stellen.

+0

Larry, Vielen Dank für die ausführliche Antwort. Was ich vorhabe ist: 1.Nach der Anmeldung mit dem oAuth-Provider sendet der Client die oAuth-Provider-ID an unseren Auth-Server. 2.Auth Server erhält entsprechende mandantId und userRole aus unserer Datenbank. 3.Auth Server generiert JWT mit mandantId und userRole und gibt es an den Client zurück. 4.Client enthält JWT in HTTP Authorization Header für jede Anfrage an unseren REST API Service –

+1

Anstatt Annahme der MandantID und Rolle vom Client, schlage ich vor, dass Sie das auf dem Server mit dem oauth Token als Ihren Schlüssel und nur zwischenspeichern Übergeben Sie das Token an/von dem Client. Andernfalls kann der Kunde diese Dinge fälschen. –

+1

Alternativ können Sie es nicht auf dem Server zwischenspeichern, sondern die Autorisierungsinformationen bei jeder Anfrage nachschlagen. Es wird weniger effizient sein, aber es ermöglicht dem Server, zustandslos zu bleiben und möglicherweise das schwierige Problem des Cache-Invalidierens zu vermeiden. –

2

Dies kann erreicht werden, indem die Anforderungen in der mittleren Ebene logisch abgefangen werden, sowohl beim Schreiben von & als auch beim Beibehalten eines mentId-Tags in jedem Dokument.

Beginnen wir mit dem Lesepfad. Angenommen, in jedem Dokument ist die Eigenschaft tenantId auf den entsprechenden Mandanten des Benutzers festgelegt, zu dem das Dokument gehört. Um Daten zu lesen, gehen Sie über die parametrisierte SQL-Abfrage (https://azure.microsoft.com/en-us/blog/announcing-sql-parameterization-in-documentdb/) und stellen Sie immer sicher, dass die Abfrage den mentId-Filter hat. Dadurch wird sichergestellt, dass die Anfrage des Benutzers nur die Mandanten-ID behandelt, auf die sich die Anfrage beziehen soll. Die Parametrisierung ist wichtig, um Injektionen zu vermeiden und dadurch Zugriff auf die Daten anderer Mandanten zu erhalten.

Auf dem Schreibpfad müssen Sie sicherstellen, dass für jedes Dokument die Eigenschaft tenantId korrekt festgelegt ist.Wenn der Endclient nicht festgelegt ist oder auch nicht, sollte der Mid-Tier diesen analysieren und sicherstellen, dass er mit dem Tenant übereinstimmt, der dem Autorisierungstoken des Benutzers entspricht, das Sie vom OAuth-Provider erhalten haben.

Beachten Sie in diesem Zusammenhang, dass der Partitionsschlüssel von mandantId helfen würde, alle Daten eines einzelnen Mandanten zusammen zu halten. Dies ist hilfreich für effiziente Abfragen im Hinblick auf die Nullsetzung auf einer einzelnen Partition, solange die Abfrage über den mandantId-Filter verfügt.

Verwandte Themen