TL;DR
OAuth 2.0 und OIDC sind de-facto-Standards für delegierte Autorisierung, enthalten aber häufige Implementierungsfehler mit kritischen Folgen. Typische Schwachstellen sind offene Redirect-URIs, fehlender CSRF-Schutz durch den state-Parameter, das Fehlen von PKCE für SPAs und mobile Apps sowie unsichere Token-Speicherung in localStorage. Access Tokens gehören in HTTPOnly-Cookies oder in Speicher ohne XSS-Zugriff. Refresh-Token-Rotation, kurze Token-Laufzeiten und Server-side Token-Invalidierung schließen die häufigsten Angriffsvektoren.
Diese Zusammenfassung wurde KI-gestützt erstellt (EU AI Act Art. 50).
Inhaltsverzeichnis (4 Abschnitte)
OAuth 2.0 ist überall: "Login with Google", "Verbinde mit GitHub", API-Zugriffe für Drittanbieter. Richtig implementiert ist OAuth sicher und bequem. Falsch implementiert entstehen kritische Sicherheitslücken - von Account-Takeover bis zu vollständiger API-Kompromittierung.
OAuth 2.0 Grundlagen - was tatsächlich passiert
OAuth 2.0 Rollen:
| Rolle | Beschreibung |
|---|---|
| Resource Owner | Der User der Zugriffsrechte erteilt |
| Client | Die Anwendung die Zugriff beantragt (z.B. Kalender-App) |
| Authorization Server | Stellt Tokens aus (Entra ID, Keycloak, Auth0) |
| Resource Server | API die mit Tokens geschützt ist (Google Calendar API) |
Authorization Code Flow (Standard für Web-Apps):
- User klickt "Login mit Google"
- Client - Authorization Server:
GET /authorize?
response_type=code&
client_id=my-app-123&
redirect_uri=https://myapp.com/callback&
scope=email+calendar.read&
state=RANDOM-CSRF-TOKEN
- User meldet sich an + genehmigt Zugriff
- Authorization Server - Client (Redirect):
GET https://myapp.com/callback?code=AUTH_CODE&state=RANDOM-CSRF-TOKEN
- Client - Authorization Server (Back-Channel):
POST /token
code=AUTH_CODE&
redirect_uri=https://myapp.com/callback&
client_id=my-app-123&
client_secret=MY-SECRET
- Authorization Server - Client:
{"access_token": "eyJ...", "expires_in": 3600}
- Client - Resource Server:
GET /calendar/events
Authorization: Bearer eyJ...
Warum Authorization Code Flow sicher ist:
- Auth Code geht über Browser (unsicher), aber nutzlos ohne Client Secret
- Access Token geht nur via Server-zu-Server (nie zum Browser)
- state-Parameter: verhindert CSRF!
Die wichtigsten OAuth-Sicherheitsprobleme
Schwachstelle 1: Offene Weiterleitungen (Open Redirects)
Problem: Der Authorization Server erlaubt beliebige redirect_uri:
GET /authorize?
response_type=code&
client_id=my-app&
redirect_uri=https://evil.com/steal
&state=...
Ergebnis: Authorization Code wird an Angreifer gesendet! Auth Code + Client Secret = vollständiger Account-Takeover.
Schutz:
redirect_uriMUSS exakt vorregistriert sein- Authorization Server muss Exact-Match prüfen (kein Wildcard!)
- Beispiel: nur
https://myapp.com/callbackerlaubt - NICHThttps://myapp.com/*, NICHThttps://*.myapp.com/callback
Schwachstelle 2: Fehlendes CSRF-Schutz (state-Parameter)
Problem: Angreifer erstellt speziell präparierten OAuth-Link mit &state=ATTACKER-CONTROLLED. Wenn der User seinen Account verbindet, wird der Angreifer-Account verbunden.
Schutz:
- state-Parameter: kryptografisch zufällig, in Session gespeichert
- Bei Callback: state aus URL = state in Session?
- Wenn nicht gleich: Angriff erkannt, Prozess abbrechen!
// Implementierung (Node.js):
const state = crypto.randomBytes(32).toString('hex');
req.session.oauthState = state;
const authUrl = `${AUTH_SERVER}/authorize?...&state=${state}`;
// Callback:
if (req.query.state !== req.session.oauthState) {
return res.status(400).json({error: 'CSRF detected!'});
}
Schwachstelle 3: Authorization Code Interception
Problem: Mobile Apps erhalten den Code via Custom URL Scheme (myapp://callback?code=AUTH_CODE). Eine andere App mit dem gleichen URL-Scheme kann den Code abfangen.
Schutz: PKCE (Proof Key for Code Exchange) - Pflicht für SPAs und Mobile!
code_verifier = 32 random bytes (geheimgehalten!)
code_challenge = BASE64URL(SHA256(code_verifier))
# 1. Start Authorization:
GET /authorize?
...&
code_challenge=<SHA256_of_verifier>&
code_challenge_method=S256
# 2. Token Request:
POST /token
code=AUTH_CODE&
code_verifier=ORIGINAL_VERIFIER
Abgefangener Auth Code ist nutzlos ohne code_verifier.
Schwachstelle 4: Unsichere Token-Speicherung
Problem: SPA speichert Access Token in localStorage - ein XSS-Angriff kann ihn auslesen.
Schutz:
- Access Token: in memory-Variablen (nicht persistent)
- Refresh Token: in HttpOnly Cookie (kein JS-Zugriff!)
- SameSite=Strict: CSRF-Schutz für Cookies
// FALSCH - XSS-anfällig:
localStorage.setItem('access_token', token);
// RICHTIG - Token in Memory:
let accessToken = null; // In-memory, verschwindet bei Reload
// Refresh Token: Server setzt HttpOnly Cookie:
res.cookie('refresh_token', refreshToken, {
httpOnly: true, // JavaScript kann nicht zugreifen
secure: true, // Nur HTTPS
sameSite: 'strict', // CSRF-Schutz
maxAge: 30 * 24 * 60 * 60 * 1000 // 30 Tage
});
Schwachstelle 5: Zu weite Scopes
Problem: App fordert alle Berechtigungen an - ein kompromittierter Token gibt Zugriff auf alles.
Schutz:
- Minimal Scope: nur was aktuell benötigt wird
- Incremental Authorization: Scope erst bei Bedarf anfordern
- Scope Transparency: User sieht was App tatsächlich braucht
// Falsch: alles auf einmal
scope: 'email profile contacts calendar drive admin'
// Richtig: nur was benötigt wird
scope: 'email' // Beim Login
// Später wenn User Kalender-Feature nutzt:
scope: 'email calendar.readonly' // Minimal!
OpenID Connect (OIDC) Sicherheit
OIDC = OAuth 2.0 + Authentifizierung (Identität):
Zusätzlich zu Access Token gibt es ein ID Token (JWT). Das ID Token enthält: sub (User ID), email, name, issued at, expiry, nonce.
OIDC-Schwachstellen
1. ID Token nicht validiert:
Problem: App vertraut ID Token ohne Signatur-Prüfung - ein gefälschter ID Token kann einen anderen User vortäuschen.
Schutz:
- IMMER signierte ID Tokens (RS256 oder ES256)
- IMMER Signatur prüfen (mit JWKS des Authorization Server)
- IMMER Expiry prüfen
- IMMER Audience (
aud) prüfen
# Python (Keycloak + python-jose):
from jose import jwks, jwt
keys = requests.get('https://keycloak/realm/certs').json()['keys']
payload = jwt.decode(
id_token,
keys,
algorithms=['RS256'],
audience='my-client-id', # Pflicht!
issuer='https://keycloak/realm'
)
2. Nonce-Replay:
Problem: Ohne nonce kann ein ID Token wiederverwendet werden. Schutz: nonce = random, in Session gespeichert - der nonce-Wert im ID Token muss dem in der Session entsprechen.
3. Implicit Flow (veraltet, unsicher):
Problem: Access + ID Token kommen direkt zum Browser via URL-Fragment - Token in URL = in Browser History, Logs, Referrer-Header. Nicht verwenden! Ersetzen durch Authorization Code Flow + PKCE.
JWT-Sicherheit (da OIDC JWTs nutzt)
JWT-Struktur: Header.Payload.Signature (base64-encoded, nicht verschlüsselt!).
JWT-Schwachstellen:
1. Algorithm Confusion (alg=none): Angriff: Header ändern zu {"alg": "none"}, Signature weglassen - unsichere Libraries akzeptieren das! Schutz: Algorithmus explizit festlegen beim Validieren, "none" niemals erlauben.
2. RS256 -> HS256 Switch: Angriff: RS256 (asymmetrisch) zu HS256 (symmetrisch) wechseln - der HS256-Schlüssel ist dann der öffentliche Schlüssel (den der Angreifer kennt!). Schutz: Algorithmus beim Validieren explizit auf RS256 fixieren.
3. Weak HS256 Secret: jwt.io Debugger + Brute-Force = geknacktes HS256 JWT. Schutz: HS256 Secret min. 256 Bit (32 Byte) zufällig; besser RS256/ES256 (asymmetrisch).
4. JWT ohne Expiry: Schutz: Immer exp Claim setzen, kurze Expiry (Access Token 15-60 Minuten).
OAuth für APIs - Client Credentials Flow
Machine-to-Machine Authentication (keine User-Interaktion):
Client Credentials Flow:
# Service A -> Authorization Server:
POST /token
grant_type=client_credentials&
client_id=service-a&
client_secret=secret123&
scope=api.read
# Authorization Server -> Service A:
{"access_token": "eyJ...", "expires_in": 3600}
# Service A -> Service B:
GET /internal-api/data
Authorization: Bearer eyJ...
Sicherheitsprobleme:
1. Client Secret Rotation:
- Secrets müssen rotiert werden (mindestens jährlich!)
- Rotation: neues Secret erstellen -> deployen -> altes deaktivieren
- Secret im Vault (nicht in Konfigurationsdatei!)
2. Scope-Kontrolle:
client_id:service-adarf NUR/api/read- Nicht: admin-API, User-Daten anderer Services
3. Mutual TLS (mTLS) statt Client Secret:
- Noch sicherer: Service A authentifiziert sich mit Zertifikat
- Client Secret: shared secret (kann geleakt werden)
- mTLS: privater Schlüssel verlässt Service nie
- Kubernetes: Istio Service Mesh mit mTLS
Best Practices Zusammenfassung:
- Authorization Code Flow + PKCE für alle Public Clients
- state-Parameter IMMER (CSRF-Schutz)
- redirect_uri: exaktes Matching, vorregistriert
- Tokens: kurze Lifetime, Refresh Token in HttpOnly Cookie
- Scopes: minimal, incremental authorization
- ID Token: immer vollständig validieren (sig + aud + exp + nonce)
- JWT: expliziter Algorithmus, kein "none", starkes Secret
- Client Secrets: in Vault, rotieren, minimale Scope
OAuth-Implementierungsfehler sind in der OWASP API Security Top 10 prominent vertreten. AWARE7 analysiert OAuth/OIDC-Implementierungen im Rahmen von Penetrationstests und Web-Application-Security-Reviews.
API-Sicherheitstest anfragen | Penetrationstest Web-Applikationen
Nächster Schritt
Unsere zertifizierten Sicherheitsexperten beraten Sie zu den Themen aus diesem Artikel, unverbindlich und kostenlos.
Kostenlos · 30 Minuten · Unverbindlich