8 Authentication

8.1 Basic Authentication

Basic Authentication ist ein einfaches, aber unsicheres Authentifizierungsschema für den Zugriff auf Webdienste oder Ressourcen. Es basiert auf dem HTTP-Protokoll und wird normalerweise in Kombination mit HTTPS verwendet, um eine gewisse Sicherheit zu bieten.

Die grundlegende Funktionsweise von Basic Authentication ist wie folgt:

  1. Der Client sendet eine HTTP-Anforderung an den Server, der geschützte Ressourcen enthält.
  2. Der Server antwortet mit dem Statuscode “401 Unauthorized” und enthält den Header “WWW-Authenticate”, der das verwendete Authentifizierungsschema angibt. Im Fall von Basic Authentication lautet der Header “WWW-Authenticate: Basic”.
  3. Der Client erkennt den “401 Unauthorized”-Statuscode und sendet erneut eine HTTP-Anforderung an den Server. Diesmal enthält die Anforderung den Header “Authorization”.
  4. Der “Authorization”-Header besteht aus dem Wort “Basic” gefolgt von einem Leerzeichen und den Anmeldeinformationen des Benutzers im Format “Benutzername:Passwort”. Diese Zeichenkette wird Base64-codiert, um sie vor einfachem Lesen zu schützen.
  5. Der Server empfängt die Anforderung und decodiert den Base64-codierten “Authorization”-Header, um Benutzername und Passwort zu extrahieren.
  6. Der Server überprüft die Anmeldeinformationen. Wenn der Benutzername und das Passwort korrekt sind, gewährt der Server Zugriff auf die angeforderten Ressourcen, indem er die HTTP-Antwort mit dem Statuscode “200 OK” zurücksendet. Andernfalls wird der Zugriff verweigert, und der Server sendet eine entsprechende Fehlerantwort.

Es ist wichtig zu beachten, dass Basic Authentication unsicher ist, da die Anmeldeinformationen bei jeder Anforderung im Base64-codierten Format über das Netzwerk gesendet werden. Da Base64 eine einfache Kodierung ist und keine Verschlüsselung, können die Anmeldeinformationen relativ leicht von Angreifern abgefangen und entschlüsselt werden. Daher wird empfohlen, sicherere Authentifizierungsmethoden wie Digest Authentication oder OAuth zu verwenden, wenn möglich.

Angenommen, wir haben einen Server mit geschützten Ressourcen und einen Benutzer mit den Anmeldeinformationen “Benutzername:Passwort”.

  1. Der Client sendet eine HTTP-Anforderung an den Server, um auf eine geschützte Ressource zuzugreifen:
GET /geschuetzte-ressource HTTP/1.1
Host: www.example.com
  1. Der Server antwortet mit dem Statuscode “401 Unauthorized” und enthält den “WWW-Authenticate”-Header:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic
  1. Der Client erkennt den “401 Unauthorized”-Statuscode und sendet erneut eine HTTP-Anforderung, diesmal mit dem “Authorization”-Header, der die Anmeldeinformationen enthält:
GET /geschuetzte-ressource HTTP/1.1
Host: www.example.com
Authorization: Basic QWxhZGRpbjpPcGVuU2VzYW1l

Der Wert des “Authorization”-Headers ist “Basic” gefolgt von einem Leerzeichen und der Base64-codierten Zeichenkette “Benutzername:Passwort” (in diesem Fall ist “Benutzername:Passwort” Base64-codiert als “QWxhZGRpbjpPcGVuU2VzYW1l”).

QWxhZGRpbjpPcGVuU2VzYW1l => base64 -d => Aladdin:OpenSesame

  1. Der Server empfängt die Anforderung und decodiert den Base64-codierten “Authorization”-Header, um Benutzername und Passwort zu extrahieren. In diesem Fall erhält der Server “Benutzername:Passwort”.

  2. Der Server überprüft die Anmeldeinformationen. Wenn die Anmeldeinformationen korrekt sind, gewährt der Server Zugriff auf die angeforderten Ressourcen und sendet die HTTP-Antwort mit dem Statuscode “200 OK”. Andernfalls verweigert der Server den Zugriff und sendet eine entsprechende Fehlerantwort.

Das ist ein grundlegendes Beispiel für die Verwendung von Basic Authentication. Es ist jedoch wichtig zu beachten, dass dieses Schema unsicher ist, da die Anmeldeinformationen im Klartext über das Netzwerk gesendet werden. Es wird dringend empfohlen, HTTPS zu verwenden, um die Kommunikation zu verschlüsseln und die Sicherheit zu verbessern.

8.2 OAuth2

OAuth2 ist ein Autorisierungsprotokoll, das es einer Anwendung ermöglicht, Zugriff auf Benutzerdaten auf einer anderen Webseite zu erhalten, ohne dass der Benutzer seine Anmeldedaten direkt der Anwendung geben muss. Stattdessen authentifiziert sich der Benutzer direkt mit dem Dienst, der seine Daten hält (zum Beispiel Google oder Facebook), und dieser Dienst erteilt der Anwendung eine begrenzte Erlaubnis, auf bestimmte Daten zuzugreifen.

OAuth2 verwendet mehrere “Flows” oder “Grants”, abhängig vom Szenario. Für diese Erklärung verwende ich das “Authorization Code Flow”, das für Server-zu-Server-Kommunikation verwendet wird.

Schritt 1: Autorisierungsanforderung

Zuerst leitet die Client-Anwendung den Benutzer an den Autorisierungsserver weiter. Dabei gibt sie ihre Client-ID, die gewünschten Zugriffsberechtigungen (Scope) und eine Redirect-URI an, auf die der Benutzer nach der Autorisierung zurückgeleitet werden soll.

GET /authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=SCOPE&state=STATE HTTP/1.1
Host: server.example.com

Schritt 2: Autorisierungszustimmung

Der Benutzer meldet sich direkt bei diesem Dienst an und stimmt der Autorisierung zu. Danach wird er an die Redirect-URI zurückgeleitet, die die Anwendung in Schritt 1 angegeben hat. In dieser Weiterleitung ist ein “Autorisierungscode” enthalten.

HTTP/1.1 302 Found
Location: https://client.example.com/cb?code=AUTHORIZATION_CODE&state=STATE

Schritt 3: Autorisierungscode-Austausch

Die Anwendung sendet jetzt einen Antrag an den Autorisierungsserver, um den Autorisierungscode gegen ein Zugriffstoken auszutauschen. In diesem Antrag muss die Anwendung ihre Client-ID und ihr Client-Geheimnis mitschicken, um ihre Identität zu bestätigen.

POST /token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&code=AUTHORIZATION_CODE&redirect_uri=REDIRECT_URI&client_id=CLIENT_ID&client_secret=CLIENT_SECRET

Schritt 4: Zugriffstoken-Erhalt

Der Autorisierungsserver prüft den Antrag und sendet ein Zugriffstoken zurück, wenn alles in Ordnung ist. Das Zugriffstoken ist das, was die Anwendung in der Zukunft verwenden wird, um auf die Benutzerdaten zuzugreifen.

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache

{
  "access_token":"ACCESS_TOKEN",
  "token_type":"bearer",
  "expires_in":3600,
  "refresh_token":"REFRESH_TOKEN",
  "scope":"SCOPE"
}

Schritt 5: Zugriff auf geschützte Ressourcen

Jetzt kann die Anwendung das Zugriffstoken verwenden, um auf die geschützten Ressourcen des Benutzers zuzugreifen. Dazu fügt sie das Zugriffstoken in den Authorization-Header

8.2.1 Beispiel - Google Kalender-Daten

Schritt 1: Autorisierungsanforderung

Die Anwendung leitet den Benutzer zu Googles Autorisierungsserver weiter. Sie stellt dabei ihre client_id, den scope (in diesem Fall Zugriff auf den Kalender) und eine redirect_uri dar, auf die der Benutzer nach der Autorisierung umgeleitet werden soll.

GET https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=YOUR_CLIENT_ID&redirect_uri=https://yourapp.com/callback&scope=https://www.googleapis.com/auth/calendar&state=123abc HTTP/1.1

Schritt 2: Autorisierungszustimmung

Der Benutzer stimmt der Autorisierung zu und wird an die redirect_uri zurückgeleitet. In dieser Umleitung ist ein Autorisierungscode enthalten.

HTTP/1.1 302 Found
Location: https://yourapp.com/callback?code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&state=123abc

Schritt 3: Autorisierungscode-Austausch

Die Anwendung sendet einen POST-Antrag an den Autorisierungsserver von Google, um den Autorisierungscode gegen ein Zugriffstoken auszutauschen. In diesem Antrag muss die Anwendung ihre client_id und client_secret mitschicken.

POST /token HTTP/1.1
Host: oauth2.googleapis.com
Content-Type: application/x-www-form-urlencoded

code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&redirect_uri=https://yourapp.com/callback&grant_type=authorization_code

Schritt 4: Zugriffstoken-Erhalt

Google prüft den Antrag und sendet ein Zugriffstoken zurück.

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache

{
  "access_token":"ya29.AHES6ZRVmB7fkLtd1XTmq6mo0S1wqZZi3-Lh_s-6Uw7p8vtgSwg",
  "token_type":"Bearer",
  "expires_in":3600,
  "refresh_token":"1/6BMfW9j53gdGImsiyUH6kU5RsR4zwI9lUVX-tqf8JXQ"
}

Schritt 5: Zugriff auf geschützte Ressourcen

Jetzt kann die Anwendung das Zugriffstoken verwenden, um auf den Kalender des Benutzers zuzugreifen. Sie fügt das Zugriffstoken in den Authorization-Header der Anfrage ein.

GET /calendar/v3/calendars/primary/events HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer ya29.AHES6ZRVmB7fkLtd1XTmq6mo0S1wqZZi3-Lh_s-6Uw7p8vtgSwg

8.2.2 JWT Token

Ein JWT (JSON Web Token) ist eine Art von Token, die oft in OAuth2 und OpenID Connect verwendet wird. Ein JWT besteht aus drei Teilen, die durch Punkte getrennt sind: Header, Payload und Signature. Hier ist ein Beispiel für einen typischen JWT:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Lassen Sie uns diesen Token in seine Komponenten zerlegen:

Header Der Header definiert den Algorithmus und den Token-Typ, der für die Signatur verwendet wurde.

{
  "alg": "HS256",
  "typ": "JWT"
}

Nachdem es in Base64 kodiert wurde, wird es zum ersten Teil des JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.

Payload (auch bekannt als Claims) Der Payload enthält die tatsächlichen Daten und Informationen des Tokens.

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}

Nachdem es in Base64 kodiert wurde, wird es zum zweiten Teil des JWT: eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.

Signature Die Signatur wird verwendet, um zu überprüfen, dass der Absender des JWT derjenige ist, der er vorgibt zu sein, und um sicherzustellen, dass die Nachricht nicht verändert wurde. Sie wird erstellt, indem man den kodierten Header, den kodierten Payload, ein Geheimnis und den Algorithmus aus dem Header zusammenführt und verschlüsselt.

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

Diese Signatur wird zum dritten Teil des JWT: SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c.

Wenn der Server das JWT erhält, kann er die Signatur überprüfen, indem er den Header und den Payload erneut verschlüsselt und sicherstellt, dass das Ergebnis mit der im Token angegebenen Signatur übereinstimmt. Wenn die Signatur übereinstimmt, weiß der Server, dass das Token legitim ist und von einer vertrauenswürdigen Quelle stammt.

8.3 Form based Authentication

Formulargestützte oder sitzungsbasierte Authentifizierung ist ein sehr verbreiteter Ansatz für die Authentifizierung in Webanwendungen. Hier sind die grundlegenden Schritte, wie sie funktioniert:

Schritt 1: Anmeldung

Der Benutzer füllt ein Anmeldeformular auf einer Webseite aus, das in der Regel einen Benutzernamen und ein Passwort enthält. Ein HTTP POST Request wird dann an den Server gesendet:

POST /login HTTP/1.1
Host: beispiel.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 44

username=benutzername&password=passwort

Schritt 2: Überprüfung

Der Server überprüft die übermittelten Anmeldedaten. Wenn die Anmeldedaten korrekt sind, erstellt der Server eine neue Sitzung und speichert sie entweder im Speicher oder in einer Datenbank auf dem Server. Diese Sitzung wird durch eine eindeutige Sitzungs-ID gekennzeichnet.

Schritt 3: Setzen des Cookies

Der Server sendet eine HTTP-Antwort an den Client und setzt ein Cookie mit der Sitzungs-ID:

HTTP/1.1 200 OK
Content-Type: text/html
Set-Cookie: sessionId=abc123; HttpOnly; Secure; SameSite=Lax

Schritt 4: Nachfolgende Anfragen

Bei jeder nachfolgenden Anfrage, die der Client an den Server sendet, wird das Sitzungs-Cookie automatisch im HTTP-Header “Cookie” mitsendet:

GET /dashboard HTTP/1.1
Host: beispiel.com
Cookie: sessionId=abc123

Schritt 5: Sitzungsüberprüfung

Bei jeder eingehenden Anfrage überprüft der Server das Sitzungs-Cookie und sucht nach der Sitzungs-ID in seiner Sitzungsspeicher. Wenn die Sitzung gefunden wird und gültig ist, wird der Benutzer als authentifiziert angesehen und die Anfrage wird fortgesetzt. Andernfalls wird der Benutzer zur Anmeldung umgeleitet oder erhält eine Fehlermeldung.

Schritt 6: Abmeldung

Wenn der Benutzer sich abmeldet, löscht der Server die Sitzung aus dem Sitzungsspeicher und setzt das Sitzungs-Cookie auf dem Client zurück.

Die Verwendung der sitzungsbasierten Authentifizierung hat sowohl Vor- als auch Nachteile. Sie ist relativ einfach zu implementieren und bietet ein hohes Maß an Kontrolle auf der Serverseite, da Sitzungen jederzeit ungültig gemacht werden können. Andererseits kann die Speicherung von Sitzungsdaten auf dem Server, insbesondere bei großen Benutzerzahlen, zu erheblichen Speicheranforderungen führen. Außerdem sind sitzungsbasierte Anwendungen in der Regel schwieriger horizontal zu skalieren.