Ich bin dabei, 3 Komponenten zu entwerfen, die in Symphonie miteinander arbeiten:
- Ein RESTful-Webdienst, der
BasicAuth
bei allen Anrufen über HTTPS erfordert und der tatsächlich das ganze schwere Heben für mein System erledigt (erledigt die Arbeit). - Eine Web-Benutzeroberfläche, die Endbenutzeraktionen in API-Aufrufe an den oben genannten Webdienst übersetzt. Daher wird die Benutzeroberfläche vom WS "unterstützt"
- Ein CLI-Tool (Command Line Interface), das Entwickler lokal installieren und ausführen können und das Befehle auch in API-Aufrufe an das WS übersetzt (daher wird es auch vom WS "unterstützt").
Eine der ersten Hürden, die ich zu überwinden versuche, betrifft die Authentifizierung und Autorisierung.
Stellen wir uns vor, der WS verwendet einen LDAP / Verzeichnisdienst (wie AD oder vielleicht Apache DS) als Authentifizierungsbereich. Das heißt, wenn ein API-Aufruf über die Leitung eingeht (z. B. HTTPS GET
für eine Ressource), werden die BasicAuth
Anmeldeinformationen aus der Anforderung extrahiert und an den LDAP-Dienst weitergeleitet, um festzustellen, ob dies ein gültiger Benutzer ist oder nicht. Wenn sie authentifiziert sind, nehmen wir an, dass ein separater Autorisierungsbereich, möglicherweise eine Datenbank, verwendet wird, um zu bestimmen, ob der identifizierte Benutzer das tun kann, was er in der HTTPS-Anforderung versucht. So weit, ist es gut.
Im Fall des CLI-Tools muss sich der Benutzer vor dem Ausführen von Befehlen authentifizieren. Daher funktioniert dieses Modell einwandfrei, da ein einzelner Benutzer immer nur dieselbe CLI-Instanz zu einem bestimmten Zeitpunkt ausführt.
Das Problem tritt auf, wenn wir versuchen, die Web-App (UI) in das WS zu integrieren, da viele Personen gleichzeitig an der App angemeldet sein können und alle unterschiedliche Berechtigungen haben, die bestimmen, welche zugrunde liegenden API-Aufrufe sie ausführen dürfen.
Soweit ich es sehe, es sieht aus wie ich habe aber 4 Möglichkeiten:
- Zwischengespeicherte Anmeldeinformationen : Nach dem Anmelden bei der App werden die Anmeldeinformationen irgendwo zwischengespeichert (sodass die App Zugriff darauf hat), und die App erzwingt selbst keine Autorisierungsrichtlinie. Wenn Benutzer versuchen, API-Aufrufe unter der Haube zu generieren, werden ihre Anmeldeinformationen aus dem Cache abgerufen und mit den API-Aufrufen weitergeleitet. Wenn der WS feststellt, dass er nicht autorisiert ist, sendet er einen Fehler zurück.
- Service-Level-Konten : Die App und der WS verwenden beide dieselben Authentifizierungs- / Autorisierungsbereiche, außer dass die Web-Benutzeroberfläche jetzt die Autorisierung für das erzwingt, was Benutzer tatsächlich in der App sehen und tun können. Wenn sie etwas tun dürfen, das einen zugrunde liegenden API-Aufruf generiert, sendet die App
myapp-admin-user
bei jedem API-Aufruf im Namen des Benutzers Anmeldeinformationen für das Dienstkonto (z. B. ). - OAuthv2 : Ich habe keine Ahnung, was OAuth ist oder ob es für dieses Szenario anwendbar ist, aber ich denke , es könnte hier irgendwie eine Lösung sein.
- Tokenserver : Verwenden Sie einen Tokenserver wie CAS oder Kerberos, um für Benutzer zu bürgen, ähnlich wie sich die Option Konto auf Serviceebene verhält. Wenn sich ein Benutzer erfolgreich bei der App anmeldet, sendet der Tokenserver der App eine Sitzungs-UUID zurück und registriert diese UUID auch beim WS. Jedes Mal, wenn die App einen API-Aufruf generiert, wird die UUID an die Anforderung angeheftet, die dann auf der WS-Seite überprüft wird.
Die Option " Zwischengespeicherte Anmeldeinformationen " fühlt sich einfach wie eine Abweichung von allem an, was im Sicherheitsland gut und gesund ist. Es fühlt sich einfach falsch an, Anmeldeinformationen überall und jederzeit zwischenzuspeichern.
Die „ Token Server “ Option scheint für einen SSO Typ Setup, aber nicht in diesem speziellen Fall gültig und fühlt sich mir peinlich. Ich denke auch, dass es keine gute Möglichkeit gibt, das Sitzungs-UUID-Konzept und BasicAuth
/ HTTPS gleichzeitig zu verwenden.
Damit bleibt OAuthv2, von dem ich nichts weiß, und " Service-Level-Konto (SLA) * " als einzige verbleibende Option übrig. Die SLA-Option scheint in Ordnung zu sein, weist jedoch einige folgende Nachteile auf:
- Es erfordert, dass das Dienstkonto grundsätzlich "Gottprivilegien" über das WS hat. Mit anderen Worten, sobald die App der Ansicht ist, dass ein Benutzer auf eine Schaltfläche klicken oder etwas in der Benutzeroberfläche tun darf, führt dies zu einem bedingungslosen API-Aufruf des von der Benutzeroberfläche verwendeten Dienstkontos. Das fühlt sich einfach schlecht an, mkay?
- Mir fällt ein, dass das Verwalten von zwei Berechtigungssätzen (der Berechtigungssatz für jeden Benutzer der App und dann der Berechtigungssatz für das von der App für das WS verwendete Dienstkonto) dazu führen kann, dass die Berechtigungen nicht mehr miteinander synchronisiert werden irgendwie
Es scheint also, dass ich hier keine wirklich guten Optionen habe. Sicherlich kann ich nicht der erste Entwickler sein, der darauf stößt, aber die Frage nach den Google-Göttern hat mir hier nicht viel geholfen. Irgendwelche Ideen?
Ich arbeite gerade an einem ähnlichen System. Ich würde lügen, wenn ich sagen würde, dass ich den "richtigen" Weg kenne, um diese Arbeit zu machen, da ich noch experimentiere, aber vielleicht könnte es helfen, über das nachzudenken, was ich für die Arbeit gefunden habe. Das Setup ist trotz seiner Nachteile , von denen ich einige diskutieren werde, ziemlich stark von OAuth2 inspiriert .
HAFTUNGSAUSSCHLUSS: Ich bin kein Sicherheitsmann von Beruf, und was ich gebaut habe, habe ich mit Hilfe von Google und so vielen Beispielen gebaut, wie ich finden konnte.
Als ich anfing zu untersuchen, wie ich die Web-API erstellen würde, die die Client-Anwendung (en) unterstützt, entschied ich, dass ich versuchen wollte, die API so zustandslos wie möglich zu machen. Ein Teil von mir war versucht, nach der HTTP-Basisauthentifizierung zu greifen und die Benutzer bei jeder Anfrage authentifizieren zu lassen, aber zwei Probleme tauchten auf, die diese Lösung nicht praktikabel erscheinen ließen:
Aufgrund der Komplexität der Authentifizierung habe ich mich für ein Tokensystem entschieden, bei dem der Benutzer eine Authentifizierungsanforderung an einen Endpunkt sendet, der ein identifizierendes Token zurückgibt und dann speichert, dass der Server es später verwenden kann, um Anforderungen zu validieren und mit ihm zu verknüpfen einige notwendige Benutzerdaten. Es ist nicht vollkommen zustandslos, und ich habe JSON-Web-Token als alternativen Ansatz betrachtet, aber die Token-Suche kann sehr schnell durchgeführt werden. (2)
Clients halten dann an diesem Token fest, bis der Server das Token nicht mehr akzeptiert. Der Client versucht dann, sich erneut beim Server zu authentifizieren und ein neues Token abzurufen, mit dem zukünftige Anforderungen authentifiziert werden können. Dies ist, was Ihr Beitrag als Strategie für zwischengespeicherte Anmeldeinformationen bezeichnet, und wir haben uns für diese Strategie entschieden, da wir dadurch mehr Kontrolle über den Zugriff auf die Anwendung behalten können. Vorausgesetzt, dem Client kann vertraut werden, dass er seine eigenen Berechtigungsinformationen besitzt und nur über eine sichere Verbindung eine Verbindung herstellt (aus diesem Grund erzwingen wir nur HTTPS-Zugriff), ist dies nicht unbedingt eine schlechte Vorgehensweise, wenn auch nur aus UX-Sicht. Für den Webdienst behalten wir das Token im lokalen Speicher des Browsers bei. Da es sich nur um eine vorübergehende Identifizierung handelt und nicht um die tatsächliche Kombination aus Benutzername und Passwort eines Benutzers, haben wir dies als "
Die Token werden dann als Teil eines Autorisierungsheaders oder als GET-Parameter für Clients an die Web-API gesendet, für die keine benutzerdefinierten HTTP-Header verfügbar sind. Dies ist wichtig, da es eine größere Flexibilität beim Zugriff auf die API aus einer Vielzahl potenzieller Clientanwendungen ermöglicht, ähnlich wie Sie eine CLI und eine Webanwendung unterstützen müssen. Inhaber-Token sind eine ziemlich häufige Sache, aber sie sind nicht gerade perfekt . Die Sicherheitsbedenken unserer Anwendung sind jedoch nicht wichtig genug, um zusätzliche Zeit für die Verbesserung aufzuwenden.
Sobald der Token validiert ist, kommt die Autorisierung ins Spiel. Was dies beinhaltet, kann sehr unterschiedlich sein, aber zu diesem Zeitpunkt in der Anwendung ist die Identität des Benutzers bekannt, und daher muss einem Autorisierungsdienst in irgendeiner Form nur die Identität des Benutzers und das Objekt / die Aktion, gegen die geprüft werden soll, gegeben werden.
Wenn Sie diese Art von Strategie verwenden möchten, gibt es zumindest viele Bibliotheken, die OAuth und OAuth2 implementieren sollen. Sofern Sie nicht wie wir sind und einige Randanforderungen haben, empfehle ich dringend, eine vertrauenswürdige Sicherheitsbibliothek von Drittanbietern zu verwenden, da Sie beim ersten Versuch höchstwahrscheinlich nicht alles richtig machen werden. Ich suche immer noch nach einer Alternative von Drittanbietern, um unser aktuelles Authentifizierungssystem zu ersetzen, da ich weiß, dass es voller Löcher und Randfälle ist, die ich mir gar nicht vorstellen kann.
Fußnoten
quelle