Eine Einführung in OAuth 2

Bei OAuth2 handelt es sich um ein weitverbreitetes Autorisierungsprotokoll, laut eigenen Angaben ein “Industry Standard”. Die neue Version 2 ist der Nachfolger der ersten, nun obsoleten Version von OAuth. Entwickelt wird OAuth von der gleichnamigen IETF OAuth Working Group. OAuth2 ist in RFC 6749 ausspezifiziert.

OAuth2 soll den Zugriff dritter Parteien auf HTTP-Services und -Ressourcen mittels einer Bestätigung durch den Benutzer und einem feingranularen Berechtigungssystem vereinfachen.

Die Kernidee ist dabei, das übliche Loginverfahren mit Username/Passwort durch ein besseres System zu ersetzen, da es beim Username/Passwort-Ansatz einige Mängel gibt. So müssen etwa die Klartextpasswörter auf einem Server der dritten Partei gespeichert werden, da sie ja für jeden Login benötigt werden. Außerdem kann der Zugriff durch die dritte Partei nicht reguliert werden. Das Resultat ist in dieser Abbildung zu sehen:

Kapselung des Ressourcenzugriffs: Zugriff ohne Kapselung und gekapselter Zugriff

Kapselung des Ressourcenzugriffs: Zugriff ohne Kapselung (oben) und gekapselter Zugriff (unten)

Mit Username/Passwort erhält das Client-Gerät direkten Zugriff auf das gesamte Benutzerkonto und alle verbundenen Ressourcen (in der Abbildung oben). Es ist nicht möglich, der dritten Partei nur Zugang zu ausgewählten Teilen oder Ressourcen zu gewähren. Dieser ressourcenlimitierende Ansatz, wie in der Abbildung unten vorgeschlagen, wäre jedoch viel sicherer und praktischer.

Bei OAuth2 werden diese für die Sicherheit eher problematischen Login-Credentials abstrahiert. Dazu gibt es mehrere Rollen, die von einem Dienst, Benutzer oder Server eingenommen werden können. Um das Zugriffsproblem zu lösen, gibt es außerdem ein Berechtigungssystem mit Einzelberechtigungen. Zusätzlich gibt es zwei grundlegende Client-Typen: Der Confidential Client und der Public Client. Aber zuerst einmal zurück zu den Rollen und dem Berechtigungssystem.

Rollen in OAuth2

Insgesamt gibt es die folgenden vier Rollen:

Resource Owner: Der Benutzer, welcher einer Anwendung den Zugriff auf seinen Account gibt.
Resource Server: Der Server des Dienstes, auf dem die Daten des Benutzers liegen. Er ist auch als API-Server bekannt.
Authorization Server: Der Server, der das Interface anzeigt, auf dem der Benutzer Anfragen erlauben und verbieten kann. Dieser Dienst kann auf demselben physischen Server, wie der Resource Server liegen.
Client: Die Anwendung, die auf den Benutzer-Account zugreifen möchte.

Feingranulare Berechtigungen

Mit OAuth2 ist es möglich, detaillierte Berechtigungen zu definieren, um Anwendungen feingranularen Zugriff auf bestimmte Funktionen und Daten der Benutzer zu geben. Damit kann der Umfang des Zugangs von Anwendungen zu den persönlichen Daten der Benutzer minimiert werden. Außerdem sieht der Benutzer detailliert, welche Anwendung auf welche seiner persönlichen Daten zugreifen kann.

Dieses Berechtigungssystem funktioniert über sogenannte Scopes. Ein Scope definiert dabei eine fixierte Menge an Berechtigungen. Beispielsweise könnte ein fiktiver Scope user:profile lauten. Dieser Scope könnte dann etwa den Zugriff auf alle Profildaten eines Benutzers ermöglichen. Auch ist damit ein Vererbungssystem umsetzbar. So könnte user:profile:email etwa in user:profile erhalten sein. Da im OAuth2-Standard jedoch nur ein einzelner String als Scope spezifiziert ist, ist dieses Berechtigungssystem anwendungsspezifisch. Ein Beispiel für so ein Scope-System ist das System von GitHub. Die dazugehörige Dokumentation ist hier zu finden.

Nach diesem Berechtigungssystem nun zum nächsten Grundlagenthema, den beiden Client-Typen Confidential Client und Public Client.

Confidential Client und Public Client

Die Anwendungen, welche über OAuth2 auf die Daten ihrer Benutzer zugreifen möchten, lassen sich allgemein in zwei Gruppen unterteilen.

Ein Confidential Client ist ein Clientprogramm, welches in der Lage ist, Geheimnisse für sich zu behalten. Dies bedeutet, dass der Quellcode und die verwendeten Ressourcen des Clients nicht öffentlich verfügbar sind und der Datenverkehr sich nicht ohne Weiteres beliebig abfangen lässt. Dem gegenüber steht der Public Client, welcher komplett öffentlich ist und keine Geheimnisse bewahren kann.

In OAuth2 erhält jeder Client zunächst einmal eine individuelle ClientId, um sich gegenüber dem Authorization Server identifizieren zu können. Beide Client-Typen enthalten diese ClientId. Zusätzlich erhält der Confidential Client noch ein geheimes Client-Secret, welches nur von Client und Authorization Server geteilt wird. Da der Public Client ja keine Geheimnisse bewahren kann, ergibt ein derartiges Secret hier keinen Sinn.

Eine Browser-Anwendung, welche komplett in JavaScript implementiert ist und im Browser läuft, ist ein Public Client. Hier ist nämlich der gesamte Quellcode inklusive eines möglicherweise integrierten kryptographischen Secrets von jedem lesbar.

Ein Beispiel für einen Confidential Client ist dagegen eine klassische WebServer-Backend-Anwendung. Hier sind Quellcode und verwendete Ressourcen (etwa eine Datei mit dem kryptographischen Secret) nicht öffentlich zugänglich und befinden sich auf dem abgesicherten Server.

Diese Unterscheidung zwischen Confidential Client und Public Client ist für OAuth2 relevant, da die beiden Typen unterschiedliche Use-Cases implizieren, für die unterschiedliche Workflows vorgesehen sind. Diese Workflows werden im Folgenden beschrieben.

Workflows

Wie oben beschrieben, gibt es für die beiden unterschiedlichen Client-Typen unterschiedliche Methoden, über welche die Authentifizierung via OAuth2 erfolgen kann. Diese Methoden werden auch ‘Workflows’ genannt. In OAuth2 werden diese über unterschiedliche ‘Authorization Grant Types’ abgebildet. So gibt es etwa den ‘Authorization Code’, die ‘Password Authentication’ oder die ‘Client Credentials’.

Vor der Verwendung eines der Workflows muss der Authorization Server zunächst mit der Third-Party-Anwendung bekannt gemacht werden. Dabei weist der Authorization Server der Anwendung eine eindeutige ClientId zu und teilt mit ihr ein Client Secret, sofern es sich bei der Third-Party-Anwendung um einen Confidential Client handelt. Wie dieser Prozess in der Praxis funktioniert, ist unten im Abschnitt “Setup einer OAuth2-Anwendung” beschrieben. Nun zu den relevanten Workflows.

Authorization Code

Beginnen wir mit dem Authorization Code. Bei dem Authorization-Code-Verfahren handelt es sich um einen zweistufigen Prozess, bei dem zunächst ein Authorization-Code erhalten wird, der dann im nächsten Schritt gegen ein Access Token getauscht wird. Hierbei werden die Zugangsdaten des Benutzers nicht benötigt, daher muss der Dienst auch kein Klartextpasswort kennen und speichern. Der in der Praxis sehr häufig anzutreffende Authorization-Code-Workflow wird im Folgenden kurz beschrieben und anschließend erläutert. Der Authorization-Code-Workflow ist in der folgenden Abbildung visualisiert:

OAuth2 Authorization-Code Workflow

OAuth2 Authorization-Code Workflow

Zunächst wird also eine Anfrage vom Client an den Server geschickt, welche den Scope (s. Berechtigungen oben) und die ClientId der Anwendung enthält. Der Authorization Server leitet den Client mit einem HTTP-Redirect weiter und gibt als Parameter den Authorization-Code mit. Dieser Authorization-Code kann anschließend in Kombination mit der ClientId und dem Client Secret gegen ein Access-Token umgetauscht werden. Mit diesem Access-Token kann schließlich der Dienst verwendet und Benutzerinformationen abgerufen und bearbeitet werden.

Bei der ersten Anfrage nach einem Authorization Code wird der betreffende Benutzer gefragt, ob er der anfragenden Anwendung die benötigten Berechtigungen erteilen möchte (siehe OAuth Notification unten). Wenn der Benutzer die Anfrage bestätigt hat, speichert der Authorization Server die zugehörige ClientId in Bezug auf den aktuellen Benutzer. Er weiß also, welche Third Party Anwendung (ClientId) auf welche Benutzerprofile zugreifen darf. Beim nächsten Mal muss der Benutzer die Anfrage daher nicht erneut bestätigen. Durch die ClientId kann der Authorization Server dann die anfragende Anwendung mit den ihm bekannten Anwendungen abgleichen und verlangt im nächsten Schritt das Client Secret zur Authentifizierung der Anwendung. Es ist also sichergestellt, dass:

  • Der Client identifizierbar ist (über die ClientId)
  • Der Benutzer dem Client irgendwann einmal erlaubt hat, auf bestimmte Berechtigungen zuzugreifen (Eintrag auf dem Authorization Server mit ClientId und Benutzerkontext)
  • Der Client der ist, für den er sich ausgibt (vorher zwischen Authorization Server und Client-Anwendung geteiltes Client Secret)

Da diese Authorisierungsmethode via Authorization Code ja auf einem kryptographischen Secret basiert, setzt sie einen Confidential Client voraus. Für Public Clients kommt daher ein etwas abgewandelter Workflow zum Einsatz. Dabei wird auf den Versand des Client-Secrets im letzten Schritt verzichtet. Da dies zu möglichen Schwachstellen führen kann, da nun nicht mehr so einfach nachgewiesen werden kann, ob der Client der ist, für den er sich ausgibt, gibt es die Proof-Key-for-Code-Exchance-Extension (PKCE). Damit wird dann wieder der zweistufige Prozess verwendet, allerdings in abgewandelter Form. PKCE ist jedoch nicht ganz trivial und wird daher in einem eigenen Artikel behandelt. PKCE stellt sicher, dass der Client, der im zweiten Schritt das Token erhalten soll, der gleiche ist, welcher im ersten Schritt den Authorization Code angefragt hat. Hierdurch sollen Man-In-The-Middle-Attacken ausgeschlossen werden.

Password Authentication

Ein weiteres, relevantes Verfahren ist die Password Authentication. Wie der Name schon sagt, wird hierbei statt einem Authorization Code ein Passwort zum Abruf des Tokens verwendet. Dieses Verfahren hebelt allerdings das gesamte Konzept der Kapselung in Scopes und der minimalen Berechtigungen aus. Er existiert hauptsächlich aus Kompatibilitätsgründen und funktioniert wie folgt:

OAuth2 Passwort Workflow

OAuth2 Passwort Workflow

Dieser Workflow ist einfacher als der Authorization-Code-Workflow und enthält nur eine POST-Anfrage an /token. Hierbei wird neben der ClientId der Benutzername und das Passwort angegeben. Zurück kommt direkt ein Access-Token.

Das Password-Authentication-Verfahren eignet sich gut für Public Clients, da hierbei kein Secret gespeichert werden muss und der Benutzer einfach seinen Benutzernamen und das Passwort eingeben kann. Dieses Verfahren wird üblicherweise auch von den zugehörigen First-Party-Apps des Dienstes selbst verwendet. So könnte etwa eine offizielle Twitter-App diese Schnittstelle der Twitter-API verwenden.

Client Credentials

Schließlich gibt es noch den Client Credentials Workflow, welcher für den Abruf von Meta-Informationen unabhängig vom Benutzer gedacht ist. Dazu gehören Daten, die keinem User sondern direkt der Anwendung gehören. Also Daten und Ressourcen, welche der Client selbst abgelegt hat und die keinem Benutzer gehören. Der Client Credentials Workflow ist nur für Confidential Clients vorgesehen und ist eine verkürzte Version des Authorization-Code-Workflows, nur eben ohne Authorization Code.

OAuth2 Client-Credentials Workflow

OAuth2 Client-Credentials Workflow

Wie aus dieser Abbildung hervorgeht, werden in diesem Workflow zunächst ClientId und Client Secret zusammen mit einem optionalen Scope an den Server gesendet, welcher gleich ein Access-Token zurückschickt. Der Umtausch eines Authorization Codes in ein solches Token entfällt damit. Natürlich kann mit diesem Token dann auch nur auf die dem Client selbst gehörenden Ressourcen zugegriffen werden, nicht etwa auf die Ressourcen eines Benutzers.

Short URL for this post: https://wp.me/p4nxik-38j
This entry was posted in Security and tagged , , , , , . Bookmark the permalink.

Leave a Reply