Auth-Optionen für verteilte Systeme

9

Ich bin dabei, 3 Komponenten zu entwerfen, die in Symphonie miteinander arbeiten:

  • Ein RESTful-Webdienst, der BasicAuthbei 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 GETfür eine Ressource), werden die BasicAuthAnmeldeinformationen 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-userbei 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?

smeeb
quelle

Antworten:

6

Es gibt viele Gründe, das grundlegende Authentifizierungsschema nicht zum Schutz von Web-API-Diensten zu verwenden.

Um den Dienst nutzen zu können, muss der Client das Passwort irgendwo im Klartext aufbewahren, um es zusammen mit jeder Anfrage zu senden.

Die Überprüfung eines Kennworts sollte sehr langsam erfolgen (um Brute-Force-Angriffen entgegenzuwirken), da dies die Skalierbarkeit Ihres Dienstes beeinträchtigen würde. Auf der anderen Seite kann die Validierung von Sicherheitstoken schnell erfolgen (Überprüfung der digitalen Signatur).

OAuth2 bietet Lösungen für jeden Ihrer Anwendungsfälle. Ihre Webanwendung kann den Code Grant verwenden , der ihr ein Zugriffstoken gibt, mit dem sie mit Ihrer API kommunizieren kann.

Ihre Webanwendung leitet den Browser des Benutzers zum Autorisierungsserver weiter. Der Benutzer wird aufgefordert, Anmeldeinformationen (oder eine Smartcard oder einen Zwei-Faktor-Authentifizierungscode) einzugeben und einen Code an den Browser zurückzugeben, mit dem der Client (Ihre Webanwendung) ein Zugriffstoken vom Autorisierungsserver abrufen kann.

Ihre Anwendung erhält außerdem ein Aktualisierungstoken zurück, mit dem sie ein neues Zugriffstoken erhalten kann, wenn das aktuelle Token abläuft.

Ihre CLI-Anwendung kann den Berechtigungsnachweis für Ressourcenbesitzer verwenden . Sie werden den Benutzer zur Eingabe von Anmeldeinformationen auffordern und diese an den Autorisierungsserver senden, um ein Zugriffs- und Aktualisierungstoken zu erhalten. Sobald Ihre CLI-Anwendung über das Token verfügt, können Sie das Kennwort des Benutzers im Speicher verwerfen.

Beide Clients (Web-App und Befehlszeilen-Client) müssen vorab beim Autorisierungsserver registriert werden.

Ihr Autorisierungsserver kommuniziert möglicherweise mit einem LDAP- / Verzeichnisdienst (Identitätsanbieter oder IdP), um die eigentliche Authentifizierung durchzuführen.

Ihr Web-API-Dienst muss nur das eingehende JWT-Token überprüfen und festlegen, was der Benutzer tun darf (Autorisierung).

Wenn Sie Opfer eines Man-in-the-Middle-Angriffs sind und Ihr Zugriffstoken verlieren, hat der Angreifer nur eine begrenzte Zeit (Token-Lebensdauer), um es zu verwenden. Ein Passwort ist normalerweise viel länger gültig. Aktualisierungstoken können widerrufen werden, falls sie verloren gehen.

MvdD
quelle
Vielen Dank für die solide Eingabe @ user18044 (+1). Was ist mit anderen HTTP-Clients für den Webdienst? Dies ist ein RESTful-Webdienst, sodass jeder Kunden dafür erstellen kann. Welche OAuthv2-Option würden diese verwenden, um jede Anforderung zu authentifizieren? Gleich wie die Web-App (Code Grant)? Danke noch einmal!
Smeeb
Können Sie auch @ user18044 bestätigen, dass OAuthv2 nur den Authentifizierungsaspekt und nicht die Autorisierung behandelt? Wenn ja, wie kann ich jede (erfolgreiche) authentifizierte Anforderung einer Reihe von Rollen / Berechtigungen zuordnen, die für den Client verfügbar sind?
Smeeb
1
Je nachdem, wie Sie diesen Clients vertrauen, werden sie unterschiedlich authentifiziert. Angenommen, Sie erstellen eine mobile Anwendung für Ihre eigene API. Sie können auch die Berechtigung für die Anmeldeinformationen des Ressourcenbesitzers verwenden. Wenn der mobile Client jedoch von einem Drittanbieter (einer App aus dem App Store) erstellt wird, verwenden Sie die implizite Gewährung.
MvdD
1
@smeeb OAuth definiert Bereiche, die angeben, was der Client tun kann. Es gibt eine Reihe vordefinierter Bereiche, aber Sie können Ihre eigenen definieren (z. B. um bestimmte APIs aufzurufen (siehe tools.ietf.org/html/rfc6749#section-3.3 )
MvdD
1
Keine Sorge, du bist willkommen. Bereiche sind wirklich ein Mechanismus, um zu bestimmen, was ein Drittanbieter in Ihrer API tun kann. Zum Beispiel eine Finanzanwendung, die nur Ihren Kontostand auf Ihrer Bank-Website lesen kann. Da das JWT-Token jedoch den Namen des Benutzers und optional sogar Rollen enthält, können Sie in einer Datenbank nachschlagen, was ein Benutzer oder Benutzer in einer Rolle tun darf. So macht es auch meine Firma.
MvdD
2

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:

  1. Das Nachschlagen zum Überprüfen der Anmeldeinformationen ist ein nicht trivialer Zeitaufwand, da bei jeder Anforderung mindestens ein Datenbankaufruf erforderlich wäre
  2. Das System ist ein mandantenfähiges System. Um zu identifizieren, zu welchem ​​Mandanten der Benutzer gehört, ist ein dritter Parameter erforderlich, der von der HTTP-Basisauthentifizierung nicht unterstützt wird (1).

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

  1. Dies wäre nicht erforderlich, wenn unser System anders aufgebaut wäre, beispielsweise indem für jeden Client unterschiedliche Einstiegspunkte verwendet würden. Alternativ habe ich auch darüber nachgedacht, klug zu werden und dem Benutzernamen eine Mandantenkennung voranzustellen
  2. Ich hatte einige Ideen, wie die Token-Zeichenfolge einfach rechnerisch validiert werden kann, anstatt eine E / A-Suche als langfristiges Ziel für Verbesserungen durchführen zu müssen. Zumindest enthalten Token ein Versionsbyte, das spätere Upgrades ermöglicht, wenn sich der Dekodierungsprozess dafür ändert
Moberemk
quelle