Warum gibt es in OAuth2 einen "Authorization Code" -Fluss, wenn der "implizite" Fluss so gut funktioniert?

263

Mit dem "impliziten" Fluss erhält der Client (wahrscheinlich ein Browser) ein Zugriffstoken, nachdem der Ressourcenbesitzer (dh der Benutzer) Zugriff gewährt hat.

Mit dem Ablauf "Autorisierungscode" erhält der Client (normalerweise ein Webserver) jedoch erst einen Autorisierungscode, nachdem der Ressourcenbesitzer (dh der Benutzer) Zugriff gewährt hat. Mit diesem Autorisierungscode ruft der Client die API erneut auf und übergibt client_id und client_secret zusammen mit dem Autorisierungscode, um das Zugriffstoken zu erhalten. Alles hier gut beschrieben .

Beide Flows haben genau das gleiche Ergebnis: ein Zugriffstoken. Der "implizite" Ablauf ist jedoch viel einfacher.

Die Frage: Warum sich mit dem Fluss "Autorisierungscode" beschäftigen, wenn "implizite" Flussnähte in Ordnung sind? Warum nicht auch "Implizit" für den Webserver verwenden?

Es ist mehr Arbeit sowohl für den Anbieter als auch für den Kunden.

Aron Woost
quelle
4
Schauen Sie sich stackoverflow.com/questions/7522831/…
Jon Nylander
1
Danke, lies es schon. Beantwortet die Frage jedoch nicht.
Aron Woost
1
Gute Frage eigentlich und selten beantwortet :) Siehe unten.
Nicolas Garnier
1
@ AaronWoost Ich denke, Sie missverstehen Server-Web-App und Browser-App
onmyway133
@entropy Das war meine Frage; Warum nicht auch den Browser-Flow für den Server verwenden?
Aron Woost

Antworten:

292

tl; dr: Das ist alles aus Sicherheitsgründen.

OAuth 2.0 wollte diese beiden Kriterien erfüllen:

  1. Sie möchten Entwicklern erlauben, Nicht-HTTPS-Umleitungs-URI zu verwenden, da nicht alle Entwickler über einen SSL-fähigen Server verfügen und dieser nicht immer ordnungsgemäß konfiguriert ist (nicht selbstsignierte, vertrauenswürdige SSL-Zertifikate, synchronisierte Serveruhr ...).
  2. Sie möchten nicht, dass Hacker Zugriffs- / Aktualisierungstoken stehlen können, indem sie Anforderungen abfangen.

Details unten:

Der implizite Ablauf ist aus Sicherheitsgründen nur in einer Browserumgebung möglich:

Im impliziten Ablauf wird das Zugriffstoken direkt als Hash-Fragment übergeben (nicht als URL-Parameter). Eine wichtige Sache beim Hash-Fragment ist, dass, sobald Sie einem Link folgen, der ein Hash-Fragment enthält, nur der Browser das Hash-Fragment kennt. Browser übergeben das Hash-Fragment direkt an die Zielwebseite (den Umleitungs-URI / die Webseite des Clients). Hash-Fragmente haben folgende Eigenschaften:

  • Sie sind nicht Teil der HTTP-Anforderung, können daher nicht von Servern gelesen werden und können daher nicht von zwischengeschalteten Servern / Routern abgefangen werden (dies ist wichtig).
  • Sie sind nur im Browser - auf der Clientseite - vorhanden. Die einzige Möglichkeit, das Hash-Fragment zu lesen, ist die Verwendung von JavaScript, das auf der Seite ausgeführt wird.

Auf diese Weise kann ein Zugriffstoken direkt an den Client übergeben werden, ohne dass das Risiko besteht, dass es von einem zwischengeschalteten Server abgefangen wird. Dies hat den Vorbehalt, nur clientseitig möglich zu sein, und benötigt Javascript, das clientseitig ausgeführt wird, um das Zugriffstoken zu verwenden.

Der implizite Datenfluss weist auch Sicherheitsprobleme auf, für deren Umgehung / Vermeidung beispielsweise weitere Logik erforderlich ist:

  • Ein Angreifer kann von einem Benutzer auf einer anderen Website / App ein Zugriffstoken erhalten (z. B. wenn er der Eigentümer der anderen Website / App ist), das Token auf seiner Website protokollieren und es dann als URL-Parameter auf Ihrer Website übergeben Identitätswechsel mit dem Benutzer auf Ihrer Website. Um dies zu vermeiden, müssen Sie die mit dem Zugriffstoken verknüpfte Client-ID überprüfen (z. B. für Google können Sie den Tokeninfo-Endpunkt verwenden), um sicherzustellen, dass dem Token Ihre eigene Client-ID (dh von Ihrer eigenen App) ausgestellt wurde, oder die Signatur überprüfen Wenn Sie ein IDToken verwenden (dies erfordert jedoch Ihr Kundengeheimnis).
  • Wenn die Authentifizierungsanforderung nicht von Ihrer eigenen Eigenschaft stammt (sogenannte Session Fixation-Angriffe), sollten Sie einen zufälligen Hash von Ihrer Website generieren, ihn in einem Cookie speichern und denselben Hash im Status-URL-Parameter von übergeben Wenn der Benutzer zurückkommt, überprüfen Sie bei der Authentifizierungsanforderung den Statusparameter mit dem Cookie und er muss übereinstimmen.

Im Autorisierungscode-Fluss ist es nicht möglich, ein Zugriffstoken direkt in einem URL-Parameter zu übergeben, da URL-Parameter Teil der HTTP-Anforderung sind. Daher können alle zwischengeschalteten Server / Router, an denen Ihre Anforderung übergeben werden könnte (möglicherweise Hunderte), dies tun Lesen Sie das Zugriffstoken, wenn Sie keine verschlüsselte Verbindung (HTTPS) verwenden, die sogenannte Man-in-the-Middle-Angriffe zulässt.

Das direkte Übergeben des Zugriffstokens an einen URL-Parameter könnte theoretisch möglich sein, aber der Authentifizierungs-Server müsste sicherstellen, dass der Umleitungs-URI HTTPS mit TLS-Verschlüsselung und einem "vertrauenswürdigen" SSL-Zertifikat verwendet (normalerweise von einer Zertifizierungsstelle, die nicht kostenlos ist). um sicherzustellen, dass der Zielserver legitim ist und die HTTP-Anforderung vollständig verschlüsselt ist. Wenn alle Entwickler ein SSL-Zertifikat erwerben und SSL in ihrer Domain ordnungsgemäß konfigurieren, wäre dies ein großer Schmerz und würde die Akzeptanz enorm verlangsamen. Aus diesem Grund wird ein einmaliger "Autorisierungscode" für die einmalige Verwendung bereitgestellt, den nur der legitime Empfänger austauschen kann (da Sie das Client-Geheimnis benötigen) und der Code für potenzielle Hacker, die die Anforderungen über unverschlüsselte Transaktionen abfangen, unbrauchbar ist (weil sie nicht '

Sie könnten auch argumentieren, dass der implizite Fluss weniger sicher ist. Es gibt potenzielle Angriffsmethoden wie das Spoofing der Domain bei der Umleitung - beispielsweise durch die Entführung der IP-Adresse der Client-Website. Dies ist einer der Gründe, warum der implizite Datenfluss nur Zugriffstoken (die nur eine begrenzte Zeit verwenden sollen) gewährt und niemals Token (die zeitlich unbegrenzt sind) aktualisiert. Um dieses Problem zu beheben, empfehle ich Ihnen, Ihre Webseiten nach Möglichkeit auf einem HTTPS-fähigen Server zu hosten.

Nicolas Garnier
quelle
12
@AndyDufresne Diese beiden Anforderungen müssen über HTTPS (obligatorisch) erfolgen, da es sich um Anforderungen an den OAuth-Server handelt, der nur HTTPS unterstützen muss. Es ist nur der Client / Anforderungsserver, der HTTPS nicht unterstützen muss, sodass Auth Codemöglicherweise nur der Server über HTTP gelöscht wird. Aber das Auth Codeist ohne die Client ID / Secret nutzlos. Grundsätzlich besteht der Punkt des OAuth-Code-Flusses darin, dass die Last eines SSL-fähigen Servers beim OAuth-Anbieter (Google / Facebook usw.) und nicht bei den Benutzern der APIs (Sie, ich) liegt.
Nicolas Garnier
5
Ok, ich folge jetzt, dass Authentifizierungscode über einfaches HTTP übertragen werden kann und das Risiko besteht, dass er beschnüffelt wird. Der Autorisierungsserver kann den Man-in-the-Middle-Angriff verhindern, indem er einen einmaligen Verwendungscode erstellt und das Clientgeheimnis für den Austausch gegen ein Zugriffstoken akzeptiert. Aber gilt das nicht auch für das Zugriffstoken? Besteht nicht das Risiko, dass der Zugriffstoken vom Hacker beschnüffelt wird, da sich der Benutzer der APIs auf einfachem HTTP befinden könnte? PS: Ich schätze Ihre Bemühungen, das Konzept zu erklären, auch nachdem es eine Weile her ist, seit dieser Thread aktiv war. Vielen Dank !
Andy Dufresne
8
no pb :) Die Anforderungen an die API - wenn das Zugriffstoken über die Leitung gesendet wird (um die Anforderung zu autorisieren) - werden ebenfalls obligatorisch über HTTPS ausgeführt. Theoretisch sollte der Client das Zugriffstoken zu keinem Zeitpunkt über das drahtlose HTTP senden.
Nicolas Garnier
5
Das Zugriffstoken in diesem Schritt ist Teil der Antwort der HTTPS-Anforderung vom Client an den Ressourcenserver. Diese Antwort ist immer noch verschlüsselt.
Nicolas Garnier
13
Grundsätzlich werden Anforderungen, die vom Client an den Ressourcenserver initiiert werden, über HTTPS ausgeführt (da der Server des Ressourceneigentümers die Unterstützung von HTTPS unterstützen muss). Es sind nur Anforderungen, die von einem anderen Ort an den Client initiiert werden und möglicherweise über HTTP ausgeführt werden (da der Client-Server HTTPS möglicherweise nicht unterstützt). Beispielsweise ist die Umleitung, die während des Authentifizierungsflusses erfolgt, nachdem der Benutzer die Berechtigung auf der Gant-Seite erteilt hat, eine Umleitung, die vom Browser zum Client-Server initiiert wurde und möglicherweise über HTTP erfolgt.
Nicolas Garnier
8

Der implizite Fluss macht den gesamten Fluss ziemlich einfach, aber auch weniger sicher .
Da die Clientanwendung, bei der es sich normalerweise um JavaScript handelt, das in einem Browser ausgeführt wird, weniger vertrauenswürdig ist, werden keine Aktualisierungstoken für einen langlebigen Zugriff zurückgegeben.
Sie sollten diesen Ablauf für Anwendungen verwenden, die temporären Zugriff (einige Stunden) auf die Benutzerdaten benötigen.
Das Zurückgeben eines Zugriffstokens an JavaScript-Clients bedeutet auch, dass Ihre browserbasierte Anwendung besondere Sorgfalt walten lassen muss. Denken Sie an XSS-Angriffe, bei denen das Zugriffstoken an andere Systeme weitergegeben werden kann.

https://labs.hybris.com/2012/06/05/oauth2-the-implicit-flow-aka-as-the-client-side-flow

Seen sind
quelle
Ich würde erwarten, dass bei einer XSS-Sicherheitsanfälligkeit selbst der Autorisierungscode-Fluss nicht viel hilft. Ich stimme jedoch zu, dass die Art und Weise, wie das Zugriffstoken im impliziten Ablauf an Javascript übergeben wird, standardisiert ist (als Hash-Fragment) und wenn auf der Website eine XSS-Sicherheitslücke besteht, ein Angriff erstellt wird, der das Zugriffstoken aus dem URL-Hash liest Fragment ist ganz einfach. Mit dem Autorisierungscode-Fluss kann andererseits eine Fälschung von standortübergreifenden Anforderungen möglich sein.
Marcel
Außerdem geht es nicht nur um Cross-Site-Scripting. Jede JavaScript-Bibliothek, die auf Ihrer Website ausgeführt wird, könnte versuchen, das Zugriffstoken zu stehlen (z. B. CDN-Bibliotheken von Drittanbietern oder Open Source-Bibliotheken, die von Ihrem Javascript-Framework verwendet werden).
Marcel
2
XSS ist jetzt kein großes Problem, wenn wir Header für Inhaltssicherheitsrichtlinien und SRI-Hashes (Sub Resource Integrity) haben.
Sergey Ponomarev
4

Aus der OAuth-Spezifikation :

4.2. Implizite Gewährung

Der implizite Grant-Typ wird verwendet, um Zugriffstoken zu erhalten (er unterstützt nicht die Ausgabe von Aktualisierungstoken) und ist für öffentliche Clients optimiert, von denen bekannt ist, dass sie einen bestimmten Umleitungs-URI betreiben. Diese Clients werden normalerweise in einem Browser mithilfe einer Skriptsprache wie JavaScript implementiert.

Da es sich um einen umleitungsbasierten Ablauf handelt, muss der Client in der Lage sein, mit dem Benutzeragenten des Ressourcenbesitzers (normalerweise einem Webbrowser) zu interagieren und eingehende Anforderungen (über die Umleitung) vom Autorisierungsserver zu empfangen.

Im Gegensatz zum Berechtigungscode-Gewährungstyp, bei dem der Client separate Anforderungen für die Autorisierung und ein Zugriffstoken stellt, erhält der Client das Zugriffstoken als Ergebnis der Autorisierungsanforderung.

Der implizite Grant-Typ enthält keine Clientauthentifizierung und hängt von der Anwesenheit des Ressourcenbesitzers und der Registrierung des Umleitungs-URI ab. Da das Zugriffstoken in den Umleitungs-URI codiert ist, kann es dem Ressourcenbesitzer und anderen Anwendungen auf demselben Gerät zugänglich gemacht werden.

Also, was können wir berücksichtigen:

  1. Dies ist für öffentliche OAuth, dh wenn der Client nicht registriert werden muss und keine eigenen Client-Geheimnisse hat. Aber welcher Authentifizierungsserver die Umleitungs-URL überprüft und dies ist tatsächlich genug für die Sicherheit.

  2. Das Zugriffstoken wird in der Adressleiste des Browsers angezeigt, sodass der Benutzer die URL kopieren und an eine andere Person senden kann. Außerdem wird es als Benutzer protokolliert, dh es handelt sich um eine Art Sitzungsfixierung. Der Browser führt jedoch eine zusätzliche Weiterleitung durch, indem er den Verlauf ersetzt, um das Hash-Fragment aus der URL zu entfernen. Es ist einem Hacker auch möglich, das Zugriffstoken durch Schnüffeln eines HTTP-Verkehrs zu stehlen, dies kann jedoch leicht durch HTTPS geschützt werden. Einige böswillige Browsererweiterungen können über die Adressleiste auf URLs zugreifen, dies ist jedoch letztendlich eine schlechte Situation wie ein defektes HTTPS-Zertifikat. Und selbst der Auth-Code-Fluss kann hier nicht helfen. Was ich also sehen kann, ist, dass das Übergeben des Zugriffstokens über ein Hash-Fragment der URL absolut sicher ist.

  3. Die Trennung von kurzlebigem Zugriffstoken und Aktualisierungstoken ist bei Verwendung eines HTTPS nutzlos und, um ehrlich zu sein, selbst bei rohem HTTP nicht so nützlich. Aber die Tatsache, dass der Client über den impliziten Fluss das Aktualisierungstoken nicht empfangen kann, ist auch Unsinn.

Daher denke ich, wir sollten einen neuen Grant-Flow "sicher implizit" einführen, der streng über https funktioniert, ein Aktualisierungstoken zulässt (oder wir sollten sie überhaupt entfernen) und dem Auth Cose-Grant-Flow vorzuziehen ist

Stokito
quelle
3

Für uns wollten unsere Kunden sich einmalig mit unserer App auf ihren Handys authentifizieren können und sich nicht wochenlang erneut anmelden müssen. Mit dem Code-Fluss erhalten Sie ein Aktualisierungstoken zusammen mit Ihrem Zugriffstoken. Der implizite Fluss gibt Ihnen kein Aktualisierungstoken. Das Zugriffstoken hat einen relativ kurzen Ablauf, die Aktualisierungstoken können jedoch bis zu 90 Tage ablaufen. Immer wenn das Zugriffstoken abläuft, können der Client- und der Servercode dieses Aktualisierungstoken verwenden, um hinter den Kulissen ein neues Zugriffstoken und ein Aktualisierungstoken zu erhalten, ohne dass der Benutzer eingreifen muss. Ein Aktualisierungstoken kann nur einmal verwendet werden. Mit Implicit Flow ist dies nicht möglich. Wenn Sie Implicit Flow verwenden und Ihr Benutzer länger als eine Stunde nicht mit Ihrer App interagiert, muss er sich erneut anmelden, wenn er zurückkommt. Das war in unserem Anwendungsfall nicht akzeptabel,

Dies funktioniert und ist sicher, da Aktualisierungstoken widerrufen werden können. Wenn ein Kunde angibt, sein Telefon oder seinen Laptop verloren zu haben oder ein Hacker auf seinen Desktop gelangt ist, können wir einfach alle Aktualisierungstoken für diesen Benutzer widerrufen. Während des gesamten Prozesses berühren niemals personenbezogene Daten (PII) unseren Code - nämlich das Passwort des Benutzers.

Der Codefluss ist fantastisch, erfordert jedoch mehr Arbeit. MS hat derzeit keine Angular-Bibliothek, daher musste ich eine schreiben. Wenn Sie interessiert sind, kann ich Ihnen dabei helfen.

Tim Hardy
quelle
2

Meine Antwort lautet: Mit dem Web-App-Server können Sie den impliziten Ablauf nicht sicher und einfach implementieren.

Der Autorisierungsprozess für Web-Apps umfasst Benutzerinteraktionen, daher sollte Authentication Server dies tun den Browser des Benutzers nach der Benutzerauthentifizierung und -einwilligung wieder auf die Zielseite der Web-App umleiten (ich sehe keine andere Möglichkeit, den Benutzer nach einer gewissen Interaktion mit der Web-App zurückzugeben Authentifizierungsserver).

Das Token sollte also über die Weiterleitungs-URL an die Web-App übergeben werden, oder?

Wie @NicolasGarnier in seiner Antwort und seinen Kommentaren erklärte, gibt es keine Möglichkeit, Token als URL-Fragment zu übergeben - es erreicht den Web-App-Server nicht.

Das Übergeben eines Tokens als URL-Parameter der Umleitungs-URL wäre selbst unter HTTPS unsicher: Wenn die Zielseite (sei es "Begrüßungsseite") Ressourcen (Bilder, Skripte usw.) enthält, werden diese Ressourcen vom Browser über die Serie abgerufen von HTTP (S) -Anfragen (von denen jede hat Referer HTTP-Header hat, der die genaue URL der "Begrüßungsseite" einschließlich der URL-Parameter enthält). Auf diese Weise kann ein Token auslaufen.

Es scheint also keine Möglichkeit zu geben, ein Token in einer Umleitungs-URL zu übergeben. Aus diesem Grund benötigen Sie einen zweiten Anruf (entweder vom Authentifizierungsserver zum Client (aber zu welcher URL?) Oder vom Client zum Authentifizierungsserver (der zweite Anruf im Ablauf des Autorisierungscodes).

Lu55
quelle