it-swarm.com.de

Warum ist es eine schlechte Idee, normales oauth2 zur Authentifizierung zu verwenden?

TL; DR : Welche Sicherheitsauswirkungen hat die Verwendung von oauth2 zur Authentifizierung?

Ich erstelle eine App (Site A), mit der Benutzer Vorgänge auf einer anderen Website (Site B) über eine einfachere Oberfläche ausführen können.

Site B bietet eine API, die OAuth2.0 für die Autorisierung meiner App implementiert.

Ich dachte, ich könnte vermeiden, Passwörter zu speichern und Benutzer dazu zu bringen, ein weiteres Konto in meiner App zu erhalten, indem ich die Authentifizierung von Site B huckepack nehme.

Natürlich habe ich gelesen die Literatur auf die Verwendung von plain OAuth zur Authentifizierung , aber ich nicht sehen, wie schlecht dies aus Sicherheitsgründen ist.

Sie scheinen sich hauptsächlich auf die Praktikabilität und (mangelnde) Allgemeingültigkeit der Lösung zu konzentrieren.

Hier ist das Schema, an das ich gedacht hatte:

  • Benutzer Sally lädt Site A und klickt auf "Login"
  • Sie wird zur Autorisierungsseite von Site B weitergeleitet, auf der sie sich entweder authentifiziert oder eine aktive Sitzung hat
  • Wenn sie Site A autorisiert, in ihrem Namen auf Site B zuzugreifen, wird sie mit einem Autorisierungscode zurück zu Site A umgeleitet
  • Standort A erhält den Autorisierungscode und tauscht ihn über die API von Standort B gegen ein Zugriffstoken (und ein Aktualisierungstoken) aus.
  • Site A fragt Site B nach Sallys Benutzer-ID und meldet sie mit dieser ID an
  • Die Token werden in einer Datenbank zur Verwendung durch ein Backend gespeichert, das die gesamte eigentliche Arbeit vor Ort B erledigt.

Ich werde bemerken, dass ich hier den sogenannten "serverseitigen Fluss" verwende. Außerdem ist der im dritten Schritt zurückgegebene authorization_code Ein kurzlebiger Einmalcode, der an die client_id von A gebunden ist und nur mit dem entsprechenden client_secret Verwendet werden kann.

Wenn sich Sally von einem anderen Gerät aus anmeldet, wird der Vorgang wiederholt und die neuen Token werden gespeichert.

Das einzige Problem, das ich sehe, ist, dass der Benutzer aufgefordert wird, meine App bei jedem Login zu autorisieren, anstatt nur beim ersten Mal, aber das ist im Moment kein Problem. Ich würde auch nach einem neuen Token fragen, wenn ich tatsächlich ein gültiges auf Lager habe. Dies ist zwar etwas unpraktisch, aber im Moment kein Problem (*) .

Was ich nicht sehe, ist, wie schlecht dies aus Sicherheitsgründen ist.

Mit einem solchen Schema: Was sind die Sicherheitsprobleme für den Benutzer? Und für die App?

Ich habe das Gefühl, etwas zu vermissen.

(*) Ich werde keine große Nutzerbasis haben, nur ein paar Whitelist-Benutzer. Wenn (wenn) die App wächst, plane ich, sie in eine größere Site zu integrieren, die einen echten OpenID Connect-Anbieter verwendet. Ich möchte es während dieses Pilottests einfach, klein und konzentriert halten

31
GnP

Hinweis : Wenn Sie nach etwas wie OAuth2 suchen, aber nach Authentifizierung suchen, sollten Sie dies tun
Verwenden Sie stattdessen OpenId Connect .


OAuth2 ist für einen Benutzer gedacht, der eine Anwendung zum Laden der Ressourcen des Benutzers von einem Ressourcenanbieter autorisiert. Mit anderen Worten: OAuth2 ist ein Mechanismus zur Delegierung der Autorisierung . Das Protokoll unterstützt keine Authentifizierung (obwohl es häufig genau dafür missbraucht wird).

Die Sicherheitslücke liegt in der Annahme, die Sie im 5. Aufzählungspunkt treffen.

Du sagst:

Site [~ # ~] a [~ # ~] fragt Site [~ # ~] b [~ # ~] nach Sallys user_id Und meldet sie mit dieser ID an

In Wirklichkeit sollte es lauten:

Site [~ # ~] a [~ # ~] fragt Site [~ # ~] b [~ # ~] nach das user_id aus den Benutzerdaten, auf die das access_token Zugriff gewährt.

(enter image description here Abbildung 1: OAuth Flow für (vertrauliche) Clients.

Wenn alles wie geplant verläuft, stammt access_token Tatsächlich von dem Benutzer, den Sie zur Authentifizierung an [~ # ~] b [~ # ~] umgeleitet haben. Aber: Es gibt keine Garantie dafür. Tatsächlich jede (böswillige) Website, der der Benutzer zuvor das Recht eingeräumt hat, auf die Daten des Benutzers zuzugreifen (unter Verwendung von OAuth2 mit [~ # ~] b [~ # ~] ). kann ein gültiges authorization_code von [~ # ~] b [~ # ~] erhalten und es Ihnen in Punkt 3 senden.

Mit anderen Worten, wenn ich eine Website betreibe, auf der Benutzer um ihre Erlaubnis gebeten werden, mit OAuth2 unter [~ # ~] b [~ # ~] auf ihre Ressourcen zuzugreifen, kann ich mich als alle ausgeben Benutzer auf allen Websites, die OAuth2 (mit [~ # ~] b [~ # ~] als OAuth2-Autorisierungsserver) zur Authentifizierung missbrauchen.

Das 'Problem' mit OAuth2 ist, dass authorization_code nicht für einen bestimmten client_id Generiert wird. Wenn Sie also einen authorization_code Erhalten, können Sie nicht sicher sein, ob [~ # ~] b [~ # ~] den authorization_code Ihnen ausgestellt hat zu Ihnen oder zu einem anderen Dienst erhalten. Was für die Autorisierung als akzeptabel angesehen wird, für die Authentifizierung jedoch absolut nicht akzeptabel ist.

Update :
Zu Ihrem Kommentar:

(und ich beschränke A darauf, nur einen von Benutzern zu akzeptieren, die zuvor zu B umgeleitet wurden, aber dies ist immer noch nicht authentifiziert)

Ich glaube, dass Sie hier eine zusätzliche Vorsichtsmaßnahme hinzufügen, die im Protokoll OAuth nicht obligatorisch) ist. Daher kann man sich nicht darauf verlassen.

32
Jacco

Wie von Jacco erklärt, weist eine naive Implementierung der Authentifizierung über oauth2 mehrere Schwachstellen auf, von denen die häufigste CSRF ist.

Angesichts der Tatsache, dass ein perfektes Authentifizierungsprotokoll ohne all diese Fallstricke verfügbar ist, ist es keine gute Idee, ein eigenes zu erstellen.

OTOH, es gibt viel zu lernen, indem man es tut und diese Probleme versteht und behebt.

TL; DR : Verwenden Sie oauth2 nicht zur Authentifizierung, es sei denn, Sie tun dies, um zu erfahren, warum Sie es nicht tun sollten. Verwenden Sie OpenID Connect.

OAuth 2.0-Bedrohungsmodell und Sicherheitsüberlegungen

In erster Linie gibt es eine umfassende Analyse des Bedrohungsmodells für oauth2 in RFC6819

Es gibt mehrere mögliche "Flows" in oauth2. Das, worauf ich mich bei meinem Projekt konzentrierte, war der authorization_code - Fluss.

Autorisierungscode"

Hier ist, was RFC6819 dazu zu sagen hat:

Ein Autorisierungscode stellt das Zwischenergebnis eines erfolgreichen Endbenutzer-Autorisierungsprozesses dar und wird vom Client verwendet, um Zugriffs- und Aktualisierungstoken zu erhalten. Autorisierungscodes werden zu zwei Zwecken anstelle von Token an die Umleitungs-URI des Clients gesendet:

  1. Browserbasierte Flows setzen Protokollparameter potenziellen Angreifern über URI-Abfrageparameter (HTTP-Referrer), den Browser-Cache oder Protokolldateieinträge zur Verfügung und können wiedergegeben werden. Um diese Bedrohung zu verringern, werden kurzlebige Autorisierungscodes anstelle von Token übergeben und über eine sicherere direkte Verbindung zwischen dem Client und dem Autorisierungsserver gegen Token ausgetauscht.

  2. Die Authentifizierung von Clients während der direkten Anforderung zwischen dem Client und dem Autorisierungsserver ist viel einfacher als im Kontext der indirekten Autorisierungsanforderung. Letzteres würde digitale Signaturen erfordern.

Autorisierungscodes sind also sicherer, yay!

authorization_code Flow-Schwachstellen werden in Abschnitt 4.4.1 von RFC6819 analysiert.

Dieser Abschnitt behandelt viel Boden. Ich werde mich nur auf einige der Bedrohungen konzentrieren.

CSRF

Aus Abschnitt 4.4.1.8:

Ein Angreifer kann einen Autorisierungscode für seine eigenen geschützten Ressourcen auf einem Autorisierungsserver autorisieren. Anschließend bricht er den Weiterleitungsfluss zum Client auf seinem Gerät ab und bringt das Opfer dazu, die Weiterleitung zurück zum Client auszuführen. Der Client empfängt die Umleitung, ruft die Token vom Autorisierungsserver ab und ordnet die Clientsitzung des Opfers den Ressourcen zu, auf die mit dem Token zugegriffen werden kann.

Auswirkung: Der Benutzer greift im Namen des Angreifers auf Ressourcen zu. [...] Beispielsweise kann der Benutzer private Elemente in die Ressourcen eines Angreifers hochladen

Dies wird auch in Abschnitt 10.12 von RFC6749 behandelt:

Der Client MUSS den CSRF-Schutz für seinen Umleitungs-URI implementieren. Dies wird normalerweise dadurch erreicht, dass jede an den Umleitungs-URI-Endpunkt gesendete Anforderung einen Wert enthalten muss, der die Anforderung an den authentifizierten Status des Benutzeragenten bindet (z. B. einen Hash des Sitzungscookies, der zur Authentifizierung des Benutzeragenten verwendet wird). Der Client sollte den Anforderungsparameter "state" verwenden, um diesen Wert an den Autorisierungsserver zu senden, wenn eine Autorisierungsanforderung gestellt wird.

Bei Ihrer Weiterleitung an den oauth2-Anbieter fügen Sie einfach einen Parameter state hinzu, bei dem es sich lediglich um ein CSRF-Token handelt (sollte nicht erraten werden können, in einem sicheren Cookie gespeichert sein usw.). Dieses Token wird zusammen mit authorization_code Zurückgesendet, wenn der oauth2-Anbieter den Benutzer zurückleitet.

Die Gegenmaßnahme für diesen Angriff muss sowohl vom Client als auch vom Autorisierungsserver implementiert werden und kann auch vom Autorisierungsserver erzwungen werden.

Der state-Parameter wird auch in diese sec.SE-Frage behandelt.

Code-Ersetzung (OAuth Login)

Dieser (in Abschnitt 4.4.1.13 von RFC6819 beschrieben) zielt speziell auf die Authentifizierung über das oauth2-Szenario ab.

Grundsätzlich erhält ein Angreifer über eine schädliche Site (nennen wir sie Site C) einen authorization_code Für den Benutzer und sendet ihn an die legitime Site (die wir immer noch Site A nennen), die ihn gegen ein access_token austauscht wird dann verwendet, um die Identität des Benutzers über den Ressourcenserver zu bestätigen. Dadurch kann sich der Angreifer effektiv als Benutzer vor Ort A anmelden.

Dies ist der von Jacco in seiner Antwort erwähnte.

Die Gegenmaßnahme für diesen Angriff muss vom Autorisierungsserver implementiert werden:

Alle Clients müssen bei jeder Anforderung, einen Autorisierungscode gegen ein Zugriffstoken auszutauschen, ihre Client-IDs angeben. Der Autorisierungsserver muss überprüfen, ob der bestimmte Autorisierungscode an den bestimmten Client ausgegeben wurde. Wenn möglich, muss der Kunde vorher authentifiziert werden.

Andere

Ob Sie es glauben oder nicht, die vorherigen Angriffe und ihre Gegenmaßnahmen decken die meisten Bedrohungen für die Authentifizierung bei Verwendung des Codeflusses ab.

Es gibt viele andere Bedrohungen und Gegenmaßnahmen, von denen viele immer umgesetzt werden sollten:

Aus Abschnitt 4.4.1.3:

Handle-basierte Token müssen eine hohe Entropie verwenden. Authentifizieren Sie den Client. Dies fügt einen weiteren Wert hinzu, den der Angreifer erraten muss. Binden Sie den Autorisierungscode an den Umleitungs-URI. Dies fügt einen weiteren Wert hinzu, den der Angreifer erraten muss. Verwenden Sie eine kurze Ablaufzeit für Token

Diese sollten alle vom Autorisierungsserver implementiert werden.

Aus Abschnitt 4.1.1.4:

Der Autorisierungsserver sollte den Client authentifizieren. Der Autorisierungsserver sollte den Umleitungs-URI des Clients anhand des vorregistrierten Umleitungs-URI validieren

Diese sollten auch vom Autorisierungsserver implementiert werden.

Aus Abschnitt 4.4.1.5, 4.4.1.6 und anderen:

der Umleitungs-URI des Clients sollte auf einen HTTPS-geschützten Endpunkt verweisen

Dieser sollte vom Client implementiert und wahrscheinlich vom Autorisierungsserver erzwungen werden.

Dann ist es in Ordnung, oauth2 für die Anmeldung zu verwenden

Nein . Tu es nicht. Verwenden Sie OpenID Connect.

Erinnern Sie sich an die Gegenmaßnahmen aus Abschnitt 4.4.1.13? Nun, es gab noch einen, den ich nicht zitiert habe:

Clients sollten ein geeignetes Protokoll wie OpenID (vgl. [OPENID]) oder SAML (vgl. [OASIS.sstc-saml-bindings-1.1]) verwenden, um die Benutzeranmeldung zu implementieren. Beide unterstützen Publikumsbeschränkungen für Kunden.

Los geht's. Verwenden Sie das stattdessen.

Wenn Sie sich weiterhin bei einem oauth2-Anbieter authentifizieren möchten/müssen, stellen Sie zunächst sicher, dass Ihr Anbieter alle oben genannten Gegenmaßnahmen implementiert.

Wenn dies der Fall ist, können Sie es möglicherweise abziehen. Testen Sie ausführlich und beauftragen Sie ein Sicherheitsteam, um eine vollständige Analyse Ihrer Lösung durchzuführen.

Stellen Sie außerdem sicher, dass alle Funktionen des Anbieters, auf die Sie sich aus Sicherheitsgründen verlassen, in der API Ihres Anbieters dokumentiert sind. Andernfalls werden sie möglicherweise ohne vorherige Ankündigung entfernt und Sie erhalten ein Very Broken ™ -Produkt.

In meinem Fall: - Ich hatte das Glück, dass mein Anbieter all diese Gegenmaßnahmen auf seiner Seite umgesetzt hat. - Ich verlasse mich bei der Authentifizierung nicht über einen ersten Testzeitraum der App hinaus darauf (dies ist keine erforderliche Funktion meiner App, sondern nur ein praktischer Platzhalter vor dem Start).

Außerdem habe ich während dieser Implementierung genug über oauth2 gelernt, damit es sich lohnt.

Wenn Sie mehr wissen möchten, lesen Sie sowohl RFC6819 als auch RFC6749. Ich fand auch diese Seite sehr nützlich.

13
GnP

Die Sicherheitslücke in Ihrem Flow:

Sie wird zur Autorisierungsseite von Site B weitergeleitet, wo sie sich entweder authentifiziert oder eine aktive Sitzung hat

Wenn der Benutzer eine aktive Sitzung an Standort B hat und andere Websites (Standort C, D usw.) das System OAuth von Standort B für ihre Autorisierung) verwenden können, handelt es sich um eine schädliche Website (z. B. Standort) x) könnte Zugriffstoken von Site B abrufen und möglicherweise die Token-Wiedergabe verwenden, um sich als Benutzer auf Ihrer Site auszugeben und Aktionen auszuführen, die nicht vom Benutzer autorisiert wurden. Lesen Sie das Facebook-Beispiel in Ihren Links erneut, um das Problem zu erklären.

Die Herausforderung bei dem gesamten Schema besteht darin, dass Ihre Site nur so sicher ist wie die OAuth API von Site B. Wie wir gerade gezeigt haben, ist ihre API nicht sicher, da Dritte sie missbrauchen können Im Falle eines Missbrauchs besteht Ihre einzige Ressource darin, an Site B zu appellieren, Site x zu verbieten. Persönlich möchte ich das Schicksal meiner Sicherheit nicht in den Händen einer Site lassen, die ich nicht besitze.

Ein sicherer Mechanismus würde die Authentifizierung Ihrer Site anhand der Liste der akzeptierten OAuth - Clients) von Site B ermöglichen, vorzugsweise mit Client-Zertifikaten mit öffentlichem Schlüssel, und die Token-Wiedergabe verhindern, indem die Token-Verwendung auf die anfordernde Site beschränkt wird Standort B kann nicht gezwungen werden, diese Art von Zugriffsschema anzuwenden. Sie sind daher auf die von ihnen bereitgestellte Sicherheitsstufe beschränkt.

1
Robert Munn