Das Video zum Artikel:
API Sicherheit aus der Perspektive eines Hackers:
Was ist ein JWT? JSON Web Tokens kurz erklärt.
Von: Till Born
Datum: 5. Sept. 2019
Aktualisiert: 17. Feb. 2021
OAuth2 wird verwendet um Autorisierung (und Authentifizierung durch Erweiterungen) und SSO (Single Sign-On) zu realisieren. Es ist dabei egal ob dies im Internet oder in der private Cloud stattfindet. Benutzer authentifizieren sich bei einem Authentifizierungsservice und können danach auf ihre Daten bei einem, an den Authentifizierungsservice gekoppelten, Service abrufen.
Schauen wir uns OAuth2 im Detail an. Wir verwenden ein fiktives Beispiel bei dem ein Benutzer seine Emails über einen Web Mail Client bei einem Web Mailer abrufen möchte. Der Web Mailer unterstützt die Annahme von OAuth2 Access Tokens und stellt bei gültigem Access Token die Emails des zugehörigen Benutzers bereit.
Der Benutzer hat einen OAuth2 kompatiblen Web Mail Client. Neben der eigentlichen OAuth2 kompatibilität muss der Client sich zuvor bei dem zu nutzenden OAuth2 Provider registrieren. Um sein Konto mit dem Client nutzen zu können muss der Benutzer sich zuerst über den Authorization Code Grant von OAuth2 anmelden. Der Authorization Code Grant wird mit einem Authentifizierungsservice durchgeführt. Hier muss der Benutzer sich mit seinem Passwort einloggen. Hat der Benutzer mit Hilfe des Clients den Authorization Code Grant durchgeführt, so erhält der Client eine temporäre Erlaubnis zum Zugriff auf die Emails die im Web Mailer hinterlegt sind. Danach stehen die Email dem Benutzer in gewöhnter Weise zu Verfügung (typische Funktionsweise eines Email-Clients).
Wir weisen den Akteuren die folgenden OAuth2 Rollen zu
Akteur | OAuth2 Rolle |
---|---|
Benutzer mit WebMail Client im Browser | Resource Owner |
Web Mail Client | Client |
Web Mailer | Resource Server |
Authentifizierungsservice | Authorization Server |
Die Rollen können von verschiedenen Parteien (z.B. Firmen) kontrolliert werden.
Es ergibt sich folgender, für den Authorization Code Grant typischer, Aufbau der Komponenten.
Abbildung :
Zum Aufbau sei folgendes erwähnt:
Die folgenden Unterkapitel beschreiben den Authorization Code Grant auf HTTP Ebene. Alle HTTP Anfragen und Antworten müssen mit TLS geschützt sein.
Der Benutzer möchte seine Mails abrufen. Er ruft die URL des Mail Service ab.
Abbildung :
Die HTTP Anfrage aus (1) sieht wie folgt aus:
Hierbei handelt es sich um den fachlichen Aufruf der Email Ressource. OAuth2 ist noch nicht involviert.
Der Client stellt fest, dass noch keine Autorisierung vorliegt und leitet den User-Agent zur Authentifizierung weiter.
Abbildung :
Die HTTP Antwort aus (2) sieht in etwa wie folgt aus:
Der User-Agent (bedient vom Resource Owner) ist beim Client nicht eingeloggt und darf deswegen nicht auf die Mails zugreifen. Der Client initiiert deswegen einen OAuth2 Grant um Autorisierung im Namen des Resource Owners zu erlangen um in dessen Namen die Resource Owner Mails abzurufen. Hierfür werden einige Parameter in die Antwort des Clients geschrieben
Teil der Nachricht | Erläuterung |
---|---|
HTTP/1.1 307 Temporary Redirect | Client leitet den User Agent zu einer anderen URL weiter |
Location: https://auth-server:7000/oauth2/auth? | Die vom User-Agent aufzurufende URL. |
client_id=abc | Teil der zuvor ausgetauschten Client Credentials - die Client ID. Hiermit tätigt der Client eine Teil-Authentifizierung indem er mitteilt welcher Client die Autorisierung beantragt. |
response_type=code | Bestimmt den gewählen OAuth2 Grant den der Client durchführen möchte. Hier wird der Authorization Code Grant über den Wert code gewählt. |
scope=openid mail | Bestimmt den Gültigkeitsbereich der Autorisierung. Hier wird geklärt, was der Client mit der Autorisierung durchführen kann. Mit den Werten openid und mail wird angegeben, dass der Client Informationen zum Benutzer und Zugriff auf dessen Mails anfragt. |
redirect_uri=https://client:2000/oauth2callback | Wurde bei der Anmeldung des Clients beim Authorization Server registriert. Der Client gibt an, wie er für den User-Agent zu erreichen ist. Die redirect_uri muss mit dem Wert übereinstimmen den der Authorization Server zur vorliegenden client_id gespeichert hat. |
state=security_token%3D3ndp324l1q2pld9cod3emhcqru%26url%3D/ | Um CSRF Angriffe zu verhindern wird ein Wert an die Anfrage angehängt der nach der Authentifizierung und dem Rückleiten auf den Client übereinstimmen muss. Einem Angreifer kann den CSRF Wert nicht einfach erraten und somit keine Angriffe auf den Benutzer durchführen um z.B. den Authorization Code durch einen anderen auszutauschen. |
Der User-Agent folgt der Weiterleitungsanfrage zum Authorization Server
Abbildung :
Die HTTP Anfrage aus (3) sieht jetzt wie folgt aus:
Es wird der authorize Endpunkt des Authorization Server aufgerufen. Die Parameter stimmen mit den Parametern aus (2) überein
Die Authentifizierung beim Authorization Server ist nicht Teil der Spezifikation. Ziel der Authentifizierung ist es, die Identität des Benutzers festzustellen (Login). Weiterhin soll dem Benutzer die Möglichkeit gegeben werden, den anfragenden Client, als auch die angefragten Scopes zu überprüfen (Zustimmung).
An dieser Stelle wird einmalig das höchste Credential des Benutzers benötigt. Das höchste Credential wäre beispielsweise das Passwort des Benutzers bei Authentifizierung mit Benutzernamen und Passwort. Eine erfolgreiche Authentifizierung setzt den gewählten OAuth2 Grant fort.
Nach der Authentifizierung wird der User-Agent mit einem Code zurück zum Client geleitet.
Abbildung :
Schauen wir uns die HTTP Antwort aus (4) an:
An dieser Stelle führt der OAuth2 Authorization Code Grant sein erstes Credential ein - den (Namensgeber) Authorization Code. Beim Authorization Code handelt es sich um ein einmalig verwendbares Token. Der Authorization Code dient als Vor-Authorisierung und ist an den Client über die Client ID gebunden. Der Authorization Code ist eine schwer erratbare zufällige Zeichenkette und hat nur einen Zweck - Tausch gegen ein anderes (dauerhafteres) Credential in einem späteren Teil des Authorization Code Grants.
Der State Wert muss mit dem Wert aus (2) übereinstimmen.
Teil der Nachricht | Erläuterung |
---|---|
HTTP/1.1 307 Temporary Redirect Location: https://client:2000/oauth2callback? |
HTTP Weiterleitung auf den Client. Die Location ist die Redirect URI die der Client bei seiner Registrierung und bei (2) angegeben hat. |
code=j67dgao1cce6tbnpk76c529vin | Der Authorization Code - ein Einmal-Token zum Tauschen gegen ein anderes Credential. |
state=security_token%3D3ndp324l1q2pld9cod3emhcqru%26url%3D/ | Muss die Wiederholung des Werts aus (2) sein. |
Der User-Agent folgt der Weiterleitung auf den Client.
Abbildung :
Die HTTP Anfrage aus (5):
Fortführung der Weiterleitung aus (4). Der User-Agent liefert den Authorization Code an den Client.
Nach Erhalt des Authorization Codes und der Überprüfung des States fordert der Client ein Access Token vom Authorization Server an.
Abbildung :
Die HTTP Anfrage aus (6) startet den Austausch des Codes für ein Access Token:
Bei Aufruf des Client Callbacks durch den Browser überprüft der Client den State um CSRF Angriffe zu vermeiden. Folgend soll der Authorization Code für das zweite OAuth2 Credentials - das Access Token - eingetauscht werden. Hierfür muss sich der Client gegenüber dem Authorization Server authentifizieren. Mit der Authentifizierung wird geprüft, ob der Client auch der ist, für den er sich ausgibt und ob der Authorization Code für diesen Client ausgestellt wurde. Die Authentifizierung findet über Basic Authentication statt.
Im Body der Anfrage stehen der einzutauschende Authorization Code, die vorherige Redirect URI und der gewählte Grant. Der Authorization Code ist der vom Authorization Server über den User-Agent erhalte Einmal-Token, der letztendlich auch die Autorisierung des Benutzers darstellt. Bei korrekten Client Credentials wird dieser gegen das dauerhaftere Access Token eingetauscht. Die Redirect URI muss erneut mit den vorherigen Werten übereinstimmen. Zuletzt kommt noch der Grant Type. Hier wird erneut der gewählte OAuth2 Grant erwähnt, damit der Authorization Server entsprechend reagieren kann.
Teil der Nachricht | Erläuterung |
---|---|
POST /oauth2/token HTTP/1.1 | Der Austausch des Authorization Codes wird als POST Anfrage durchgeführt. Es wird der Token Endpunkt des Authorization Servers aufgerufen |
Content-Type: application/x-www-form-urlencoded | Encoding des Bodies der Anfrage |
Authorization: Basic YWJjOmRlZg== | Hier sind die Client Credentials im Basic Authentication Format hinterlegt. Es werden die Werte client_id (abc) und client_secret (def) Base64 kodiert. |
code=j67dgao1cce6tbnpk76c529vin | Der auszutauschende Authorization Code |
redirect_uri=https://client:2000/oauth2callback | Die Redirect URI aus der Registrierung des Clients, aus (2), aus (4) und aus (5) |
grant_type=authorization_code | Teilt den ausgewählten OAuth2 Grant mit. Hier Authorization Code Grant. |
Der Authorization Server stellt das Access Token für den Client aus.
Abbildung :
Der Authorization Server antwortet in (7) mit einem JSON bestehend aus der Autorisierung:
Mit Erhalt des Access Tokens bekommt der Client die Autorisierung im Namen des Benutzers eine Aktion durchzuführen. Es handelt sich in diesem Beispiel wieder um eine schwer erratbare zufällige Zeichenkette. Das Access Token hat eine kurze Lebensdauer und ist Ersatz für die Benutzer Credentials. Die Lebensdauer wird über den expires_in Wert bereitgestellt. Der Typ des Tokens ist Bearer. Der Bearer Typ gibt 3 Möglichkeiten vor, wie das Access Token dem Resource Server präsentiert werden kann (Authorization Header, Body Payload und als Query Parameter). Der für dieses Access Token gewährte Gültigkeitsbereich wird im Scope Parameter beschrieben. Es wurden die selben Scopes gewährt, wie die, die angefragt wurden. Der Authorization Server könnte hier ggf. den Scope weiter einschränken, z.B. anhand der Client ID. Läuft ein Access Token ab muss nicht erneut der gesamte OAuth2 Grant durchlaufen werden. Über das Refresh Token kann erneut ein Access Token erfragt werden. Hierfür wird ein separater Grant durchgeführt. Durch den Scope Wert openid wurden implizit Informationen zum Authentifizierungsereignis des Benutzers bereitgestellt. Diese werden als JWT in compact serialization im ID Token übergeben. Hierdurch kann ein Client Informationen zum Benutzer an den Resource Server übermitteln.
Teil der Nachricht | Erläuterung |
---|---|
HTTP/1.1 200 Ok | Erfolgsmeldung zum Eintausch des Authorization Codes für das Access Token |
Cache-Control: no-store | Die Anfrage und Antwort sollen nicht gecacht werden. |
Pragma: no-cache | Kompatibilität: Eigentlich nur für Anfragen gültig, wird hier aber in der Antwort gesetzt und hat semantisch die selbe Auswirkung wie Cache-Control: no-cache |
"access_token":"tl9jckcemkk4t3mrcujkj41260" | Das Access Token ermöglicht dem Client im Namen des Benutzers auf den Resource Server zuzugreifen. Der Client hat es im Austausch für den Authorization Code erhalten. |
"token_type":"Bearer" | Gibt die Art und die Verwendungsmöglichkeiten des Access Tokens an. |
"expires_in":900 | Gibt die Lebensdauer des Tokens in Sekunden an. Hier 15 Minuten. |
"scope":"openid profile" | Der gewährte Gültigkeitsbereich des Access Tokens. |
"refresh_token":"pc2movr8gls98er4e66ghhjpqi" | Ermöglicht die Erneuerung der Autorisierung durch Erneuerung des Access Tokens |
"id_token":"eyJraWQiOiJsdXRhYXVxMGE2ajdlOXI1Zm1lYWR…KfBHxRqpAlpfC3i2SmLxEev2SynrDqxmw" | Nicht Teil von OAuth2, sondern von OpenID Connect Core Bereitstellung von Informationen zur Authentifizierung des Benutzers. Das Token ist hier nicht vollständig, sondern mit ... in der Mitte gekürzt. |
Hiermit endet die Spezifikation zu OAuth2. Es bleiben aber einige Fragen unbeantwortet, z.B.:
Mögliche Varianten folgen und werden teilweise mit OpenID Connect Core beantwortet
Der Client ruft die Mails Ressource auf
Abbildung :
Eine beispielhafte HTTP Anfrage für (8) ist folgend aufgeführt:
Wichtig: Die Spezifikation enthält keine Angaben, wie der Aufruf des Resource Server erfolgt.
Die Anfrage enthält mehrere Möglichkeiten wie der Resource Server angesprochen werden kann. Sind Client und Resource Server nicht unter Kontrolle von verschiedenen Parteien so ist es völlig frei, ob das Access Token, ein User Identifier, die Email o.ä. übertragen wird. Hier muss der Resource Server nur mit einer der Möglichkeiten umgehen können und der Client sicherstellen, dass keiner der Header ohne Kontrolle von außen eingespielt werden kann.
In der Abbildung angedeutet ist der Fall, dass das Access Token mit der Anfrage mitgeschickt wird. Dieses würde im Format Authorization: Bearer {TOKEN} als Header mitgeliefert werden (Bearer Token Usage, RFC 6750).
Der Client hat der Anfrage ausreichend Informationen beigelegt damit der Resource Server seine Arbeit vervollständigen kann. Hier kann das Access Token ausreichen, ggf. wurde Benutzername oder Email mitgeschickt.
Der Resource Server antwortet mit den Emails.
Abbildung :
Die HTTP Antworten aus (9) und (10) haben keine OAuth2 spezifischen Angaben, sondern beinhalten die fachliche Antwort der Gegenseite:
Die Emails werden an den User-Agent übergeben.
Über den User-Agent wird erneut eine Anfrage an den Resource Server gesendet.
Abbildung :
Nach erfolgreicher Autorisierung ruft der User-Agent erneut den Client auf. Der Client hatte zuvor eine Session angelegt und diese im Cookie Header hinterlegt. (1) Bei folgenden Anfragen kennt der Client den User-Agent bereits und kann dann in (2) z.B. direkt das Access Token an die Anfrage anhängen. (3) und (4) verhalten sich wie zuvor - es werden die Emails übermittelt.
Hinweis: Das Access Token hat nur eine geringe Lebensdauer und muss gelegentlich vom Client erneuert werden. Hierfür kann das Refresh Token oder eine erneute Durchführung des Authorization Code Grants genutzt werden.
In diesem Artikel wurde der Authorization Code Grant im Detail auf HTTP Ebene aufgezeigt. Der Ablauf wird durch den Client initiiert, gefolgt von der Authentifizierung des Resource Owners, Ausgabe des Authorization Codes und Austausch des Access Tokens. Es wurde klar, dass die Benutzer Credentials nur beim Authorization Server überprüft werden und die weitere Autorisierung über das Access Token stattfindet.
Doch wie wird die Autorisierung überprüft? Das OAuth2 Framework lässt hier Fragen offen die über weitere Spezifikationen zu klären sind. Die OAuth 2.0 Token Introspection als auch die OpenID Connect Core Spezifikation liefern hier weitere Informationen.
Das Video zum Artikel:
API Sicherheit aus der Perspektive eines Hackers:
Was ist ein JWT? JSON Web Tokens kurz erklärt.
Erfahre mehr zu OAuth2 und OIDC in der Schulung zur API Sicherheit.