🔑 OAuth 2.0

OAuth 2.0 ist der am häufigsten verwendete Autorisierungsrahmen für den API-Zugang. Die Auswahl des geeigneten Berechtigungstyps ist entscheidend.

Auswahl einer Förderungsart

Art der Finanzhilfe Anwendungsfall Sicherheitsstufe
Authorization Code + PKCE SPAs und mobile Anwendungen (empfohlen) Höchste
Authorization Code Server-seitige Webanwendungen Hoch
Client Credentials Server-zu-Server-Kommunikation (M2M) Mittel
Implizit (veraltet) Ältere SPAs Niedrig
Passwort des Ressourcenbesitzers (veraltet) Höchste Vertrauenswürdigkeit nur bei Erstanbietern Niedrig
Keine implizite Gewährung verwenden

Implizites Grant ist jetzt veraltet, da das Token im URL-Fragment offengelegt wird. Verwenden Sie Autorisierungscode + PKCE für SPAs.

Berechtigungscode + PKCE-Flow

JavaScript PKCE Herausforderung Generation
// 1. zufällige Generierung von code_verifier
function generateCodeVerifier() {
  const array = new Uint8Array(32);
  crypto.getRandomValues(array);
  return btoa(String.fromCharCode(...array))
    .replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
}

// 2. code_challenge mit SHA-256 generieren
async function generateCodeChallenge(verifier) {
  const encoder = new TextEncoder();
  const data = encoder.encode(verifier);
  const digest = await crypto.subtle.digest('SHA-256', data);
  return btoa(String.fromCharCode(...new Uint8Array(digest)))
    .replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
}

// 3. autorisierungsanfrage
const verifier = generateCodeVerifier();
const challenge = await generateCodeChallenge(verifier);

const authUrl = `https://auth.example.com/authorize?` +
  `response_type=code&` +
  `client_id=${clientId}&` +
  `redirect_uri=${redirectUri}&` +
  `code_challenge=${challenge}&` +
  `code_challenge_method=S256&` +
  `scope=read write`;

🎫 JWT (JSON Web Token)

JWT ist als zustandsloses Authentifizierungs-Token weit verbreitet, aber Implementierungsfehler führen direkt zu Sicherheitslücken.

JWT-Sicherheitsüberlegungen

✅ Tun

  • Explizite Angabe des Algorithmus (HS256 / RS256)
  • Legen Sie eine kurze Verfallszeit (15 Minuten oder weniger) fest.
  • Validierung des Ausstellers (issuer) und der Zielgruppe (aud)
  • Generieren Sie geheime Schlüssel mit ausreichender Länge (256 Bit oder mehr)
  • Implementierung der Rotation für Refresh-Tokens

❌ Nicht

  • Speicherung sensibler Informationen in der JWT-Nutzlast (Base64 ist keine Verschlüsselung)
  • Erlaube alg: "keine"
  • Token in localStorage speichern (anfällig für XSS)
  • Vernachlässigung des Token-Widerrufsmanagements
  • Verwendung eines öffentlichen RS256-Schlüssels als HS256-Geheimschlüssel

Sichere JWT-Implementierung

JavaScript (Node.js) Token-Ausgabe und Verifizierung
const jwt = require('jsonwebtoken');

// Token-Ausgabe ---
function issueTokens(user) {
  const accessToken = jwt.sign(
    { sub: user.id, role: user.role },
    process.env.JWT_SECRET,
    {
      algorithm: 'HS256',
      expiresIn: '15m',
      issuer: 'api.example.com',
      audience: 'app.example.com',
    }
  );

  const refreshToken = jwt.sign(
    { sub: user.id, type: 'refresh' },
    process.env.REFRESH_SECRET,
    { algorithm: 'HS256', expiresIn: '7d' }
  );

  return { accessToken, refreshToken };
}

// Token-Prüfung ---
function verifyAccessToken(token) {
  return jwt.verify(token, process.env.JWT_SECRET, {
    algorithms: ['HS256'],   // ← Immer angeben!
    issuer: 'api.example.com',
    audience: 'app.example.com',
  });
}

Token-Speicherplatz-Vergleich

Speicherort XSS-Widerstand CSRF-Widerstand Empfehlung
HttpOnly Cookie △ (erfordert SameSite-Einstellung) Empfohlen
Speicher (variabel) Navigation auf der Seite verloren
localStorage ✕ (kann über XSS gestohlen werden) Nicht empfohlen
sessionStorage ✕ (kann über XSS gestohlen werden) Eingeschränkte Nutzung
Empfohlen: HttpOnly + Sicher + SameSite Cookie

Die Speicherung des Zugriffstokens in einem Cookie mit den Attributen HttpOnly, Secure und SameSite=Strict ist der sicherste Ansatz. Dies verhindert den Diebstahl des Tokens durch XSS-Angriffe.

🗝 API-Schlüsselverwaltung

API-Schlüssel sind ein einfacher Authentifizierungsmechanismus, aber eine unsachgemäße Verwaltung kann zu ernsthaften Risiken führen.

Bewährte Praktiken für API-Schlüssel

Erzeugung und Speicherung

Generieren Sie mit ausreichender Entropie (256 Bit oder mehr). Gehashte Daten speichern; niemals reinen Text in der Datenbank aufbewahren.

Einschränkung des Geltungsbereichs

Weisen Sie jedem Schlüssel einen Mindestumfang zu (nur Lesezugriff, nur bestimmte Ressourcen usw.). Vermeiden Sie Wildcard-Berechtigungen.

Drehung

Wechseln Sie die Schlüssel regelmäßig (innerhalb von 90 Tagen). Setzen Sie eine Schonfrist für alte Schlüssel. Sofortiger Widerruf bei Auslaufen.

Übertragungsverfahren

Senden Sie per Header (X-API-Key oder Authorization). Nicht in URL-Abfrageparameter aufnehmen (sie erscheinen in den Protokollen).

Verwaltung von Umgebungsvariablen

Schreiben Sie die Schlüssel nicht fest in den Quellcode. Verwalten Sie sie mit Umgebungsvariablen oder einem Secret Manager.

Überwachung und Protokollierung

Überwachen Sie die Verwendung von API-Schlüsseln. Erkennen Sie anomale Muster (Massenanfragen, Zugriff von unbekannten IPs).

Beispiel für die Implementierung der API-Schlüsselvalidierung

JavaScript (Express) Validierung von Hash-API-Schlüsseln
const crypto = require('crypto');

// Hash des API-Schlüssels mit SHA-256 und Vergleich
async function validateApiKey(req, res, next) {
  const apiKey = req.headers['x-api-key'];
  if (!apiKey) {
    return res.status(401).json({ error: 'API key required' });
  }

  // Hash und Nachschlagen in DB (timingSafeEqual nicht erforderlich, da wir Hashes vergleichen)
  const hashedKey = crypto
    .createHash('sha256')
    .update(apiKey)
    .digest('hex');

  const keyRecord = await db.findApiKey(hashedKey);

  if (!keyRecord || keyRecord.revokedAt) {
    return res.status(403).json({ error: 'Invalid API key' });
  }

  // Verfall prüfen
  if (keyRecord.expiresAt && new Date() > keyRecord.expiresAt) {
    return res.status(403).json({ error: 'API key expired' });
  }

  req.apiClient = keyRecord;
  next();
}

🤖 Securing LLM & AI Agent API Access

AI agents and LLM-powered applications require additional authentication and authorization patterns beyond traditional API security.

Model-Specific Scopes

Assign different access levels per model tier (e.g., GPT-4 requires elevated scope). Prevent unauthorized use of expensive or sensitive models.

Token Budget Enforcement

Embed token budgets in access tokens or API key metadata. Enforce per-request and per-day limits to prevent denial-of-wallet attacks.

Prompt-Level Authorization

Check user permissions before executing certain prompt types (e.g., code generation, data analysis). Map prompt categories to role-based permissions.

Multi-Tenant Isolation

Ensure conversation history, fine-tuned models, and RAG data are isolated per tenant. Use tenant-scoped API keys with namespace enforcement.

Agent Identity & Attestation

Assign cryptographic identities to AI agents. Use signed JWTs for inter-agent communication. Verify agent identity before granting tool access.

Credential Rotation for AI Services

Automate API key rotation for LLM providers. Use short-lived tokens for agent sessions. Revoke credentials immediately when agents are decommissioned.

Agent Tool Access Authorization

Scenario Auth Method Required Scope Approval
Agent reads public data API Key data:read Automatic
Agent modifies user data OAuth 2.0 (delegated) data:write User consent required
Agent calls external API OAuth 2.0 + mTLS external:invoke Human-in-the-loop
Agent executes code / shell Scoped JWT + Sandbox exec:sandbox Admin approval + audit log

Scoped OAuth Token for AI Agents (Python)

Python Agent Token Issuance with Scope Enforcement
import jwt
import time
from datetime import datetime, timedelta

class AgentTokenIssuer:
    """Issues scoped, short-lived tokens for AI agents."""

    ALLOWED_SCOPES = {
        "reader": ["data:read"],
        "writer": ["data:read", "data:write"],
        "executor": ["data:read", "data:write", "exec:sandbox"],
    }

    def __init__(self, secret_key: str):
        self.secret_key = secret_key

    def issue_agent_token(
        self,
        agent_id: str,
        role: str,
        tenant_id: str,
        token_budget: int = 10000,
        ttl_minutes: int = 15,
    ) -> str:
        # Validate role and resolve scopes
        if role not in self.ALLOWED_SCOPES:
            raise ValueError(f"Invalid role: {role}")

        payload = {
            "sub": agent_id,
            "tenant": tenant_id,
            "scopes": self.ALLOWED_SCOPES[role],
            "token_budget": token_budget,
            "iat": datetime.utcnow(),
            "exp": datetime.utcnow() + timedelta(minutes=ttl_minutes),
            "type": "agent",
        }
        return jwt.encode(payload, self.secret_key, algorithm="HS256")

    def verify_tool_access(self, token: str, required_scope: str) -> dict:
        # Decode and verify agent token
        payload = jwt.decode(
            token, self.secret_key, algorithms=["HS256"]
        )
        if required_scope not in payload["scopes"]:
            raise PermissionError(
                f"Agent {payload['sub']} lacks scope: {required_scope}"
            )
        return payload
OWASP References

Related: LLM06: Excessive Agency, ASI01: Excessive Agency, ASI03: Insecure Tool/Function Calling

Vergleich der Authentifizierungsmethoden

Methode Zustandslos Anwendungsfall Überlegungen zur Sicherheit
OAuth 2.0 + PKCE APIs, die eine Benutzerautorisierung erfordern Status/PKCE erforderlich, Verwaltung des Token-Ablaufs
JWT Bearer Dienstübergreifende Kommunikation Algorithmus-Spezifikation erforderlich, keine sensiblen Daten in der Nutzlast
API-Schlüssel Server-zu-Server, externe Integrationen Rotation und Einschränkung des Geltungsbereichs erforderlich
mTLS Hochsichere M2M-Kommunikation Hohe Betriebskosten für das Zertifikatsmanagement
Sitzungs-Cookie Traditionelle Webanwendungen CSRF-Schutz erforderlich, Herausforderungen bei der Skalierbarkeit