Ausführliche Anleitung zu API-Security

In diesem Dokument wird ausführlich erklärt, wie man APIs sicher gestaltet. Dabei werden Transportsicherheit, API-Authentisierung und zielgerichtete Autorisierung beleuchtet. Ziel ist es, einen umfassenden Einblick zu geben, wie man diese Sicherheitsaspekte technisch umsetzt.


1. Transportsicherheit

1.1 TLS (Transport Layer Security)

  • HTTP/1.x & HTTP/2 (über TLS 1.2 oder TLS 1.3)
  • HTTP/3 (basiert auf QUIC und nutzt TLS 1.3)

Grundsätzlich sollte jede Kommunikation zwischen Client und Server verschlüsselt erfolgen. TLS (früher SSL) gewährleistet die Vertraulichkeit und Integrität der übertragenen Daten. Im Kontext von APIs wird HTTPS (HTTP über TLS) verwendet.

1.1.1 Zertifikate

Damit TLS funktioniert, benötigt der Server ein digitales Zertifikat. Die gängigsten Zertifikatsvarianten sind:

  • Selbstsignierte Zertifikate: Eignen sich eher für Test- oder Entwicklungsumgebungen, da sie nicht von einer vertrauenswürdigen CA (Certificate Authority) signiert werden.
  • Zertifikate einer CA: Werden von einer offiziell anerkannten Zertifizierungsstelle (z. B. Let’s Encrypt, DigiCert) ausgestellt und sind für Produktionsumgebungen essenziell.

Beispiel (Nginx-Konfiguration):

server {
    listen 443 ssl http2;
    server_name example.com;
    ssl_certificate /etc/ssl/certs/example.crt;
    ssl_certificate_key /etc/ssl/private/example.key;
 
    location / {
        proxy_pass http://localhost:8080;
    }
}

1.2 HTTP/3 und QUIC

  • QUIC ist ein von Google entwickeltes Transportprotokoll, das standardmäßig auf TLS 1.3 setzt.
  • Vorteil: Schnellerer Verbindungsaufbau, da das TLS-Handshake-Verfahren in QUIC integriert ist.
  • Noch nicht in allen Umgebungen (z. B. bei jedem Hosting-Provider) zu 100 % etabliert, aber es gewinnt stetig an Verbreitung.

1.3 VPN (Virtual Private Network)

  • Intranet oder geschütztes Netzwerk: APIs können zusätzlich abgesichert werden, indem man sie nur über ein internes Netzwerk oder VPN zugänglich macht.
  • Tunnelverschlüsselung: Ein VPN gewährleistet, dass sämtliche IP-Pakete verschlüsselt durch das öffentliche Netz laufen.
  • Beispiel: IPSec, OpenVPN oder WireGuard.

Zusammengefasst bildet die Transportsicherheit das Fundament für alle weiteren Sicherheitsmechanismen. Selbst wenn eine API eine starke Authentifizierung besitzt, sollte die Kommunikation stets verschlüsselt erfolgen, um Abhören und Manipulation zu verhindern.


2. API-Authentisierung

Um sicherzustellen, dass nur legitime und autorisierte Nutzer auf die API zugreifen, sind verschiedene Verfahren der Authentifizierung möglich. Hier wird zwischen Basic Auth, API-Keys und OAuth 2.0 unterschieden.

2.1 Basic Auth (mit HTTPS)

  • Funktionsweise:
    • Der Client sendet im HTTP-Header Authorization: Basic <Base64-codiertes "user:pass">.
    • Beispiel: Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== (hier fiktiv “Aladdin:open sesame”).
  • Wichtig: Basic Auth muss über HTTPS erfolgen, da Benutzername und Passwort ansonsten im Klartext übertragen werden.
  • Implementierung:
    1. Server validiert Benutzername/Passwort.
    2. Bei Erfolg: Zugriff auf API-Endpunkte gewähren.
    3. Bei Fehlschlag: 401 Unauthorized.

Beispiel (Node.js Express)

app.use((req, res, next) => {
  const authHeader = req.headers['authorization'];
  if (!authHeader) {
    res.set('WWW-Authenticate', 'Basic realm="Restricted"');
    return res.status(401).send('Not authorized');
  }
 
  const base64Credentials = authHeader.split(' ')[1];
  const credentials = Buffer.from(base64Credentials, 'base64').toString('ascii');
  const [username, password] = credentials.split(':');
 
  if (username === 'admin' && password === 'secret') {
    return next();
  } else {
    res.set('WWW-Authenticate', 'Basic realm="Restricted"');
    return res.status(401).send('Not authorized');
  }
});

2.2 API-Keys

  • Definition: Ein API-Key ist ein eindeutiger Schlüssel (oft ein zufälliger String), der einem Nutzer oder einer Anwendung zugeordnet wird.
  • Verwendung: Der Key wird üblicherweise im HTTP-Header, URL-Query oder als Teil des Anfragepfads mitgeschickt.
    • GET /api/resource?api_key=abc123
    • oder per Header: Authorization: ApiKey abc123
  • Vorteile:
    • Einfache Einrichtung.
    • Ausreichend für einfache Anwendungen oder interne Services.
  • Nachteile:
    • Kein Mechanismus zur Delegation oder unterschiedliche Berechtigungsstufen pro Key.
    • Für komplexere Rollen- und Zugriffskonzepte ist eine andere Lösung (OAuth, JWT) oft besser.

Beispiel (Header-Based)

app.use((req, res, next) => {
  const apiKey = req.headers['x-api-key'];
  if (apiKey === 'meinGeheimerApiKey') {
    return next();
  } else {
    return res.status(403).send('Forbidden');
  }
});

2.3 OAuth 2.0

  • De-facto-Standard für viele öffentliche APIs (z. B. Google, Facebook, GitHub).
  • Grundidee: Statt Benutzernamen/Passwort direkt weiterzugeben, erhält der Client ein Token (z. B. Access Token), das verschiedene Zugriffsrechte haben kann.
  • Flows (vereinfachter Überblick):
    1. Authorization Code Flow: Typisch für Web-Anwendungen, bei denen der Nutzer in einem Browser eingeloggt wird.
    2. Client Credentials Flow: Für Machine-to-Machine-Kommunikation (z. B. Microservices).
    3. Resource Owner Password Flow: Veraltet und wird zunehmend durch andere Flows ersetzt.
  • JWT (JSON Web Token): In vielen OAuth 2.0 Implementierungen werden JWTs verwendet, um den Nutzer und seine Berechtigungen abzusichern.

Beispiel (Client Credentials Flow)

  1. Client sendet client_id und client_secret an den Authorization Server.
  2. Server prüft Validität und gibt ein Access Token zurück.
  3. Client nutzt das Access Token im HTTP-Header Authorization: Bearer <Token> für API-Anfragen.
# Token anfordern
curl -X POST \
  -H "Content-Type: application/json" \
  -d '{"client_id":"abc","client_secret":"123","grant_type":"client_credentials"}' \
  https://auth.example.com/oauth/token
# API mit Access Token aufrufen
curl -X GET \
  -H "Authorization: Bearer eyJhbGciOi..." \
  https://api.example.com/resource

3. Gezielte Autorisierung

Während die Authentisierung die Identität eines Nutzers oder Services bestätigt, regelt die Autorisierung, welche Aktionen dieser Nutzer ausführen darf.

3.1 Rollenbasierte Zugriffskontrolle (Role-Based Access Control, RBAC)

  • RBAC: Nutzer werden Rollen (z. B. Admin, User, Editor) zugewiesen, die bestimmte Rechte definieren.
  • Vorteil: Leicht verständlich und einfach in vielen Systemen umzusetzen.
  • Beispiel:
    • Admin-Rolle darf: Daten anlegen, bearbeiten, löschen.
    • Editor-Rolle darf: Daten bearbeiten.
    • User-Rolle darf: Daten lesen.

3.2 Attributbasierte Zugriffskontrolle (Attribute-Based Access Control, ABAC)

  • ABAC berücksichtigt Eigenschaften (Attribute) des Nutzers (z. B. Abteilung, Projektnummer, Zeitpunkt, Standort) sowie des angeforderten Objekts.
  • Feingranulare Steuerung: Beispiel: “Alle Mitarbeiter der Abteilung X dürfen nur zwischen 08:00 und 18:00 Uhr auf bestimmte Ressourcen zugreifen.”.

3.3 Richtliniendefinition

  • Policies: Können in einer zentralen Komponente (z. B. “Policy Decision Point”) definiert und ausgewertet werden.
  • Entscheidungsfindung: Der API-Gateway oder ein Microservice fragt diese zentrale Komponente an, ob eine gewünschte Aktion erlaubt ist.

Fazit

Eine sichere API-Umgebung setzt sich aus mehreren Bausteinen zusammen:

  1. Transportsicherheit (TLS): Verschlüsselung der Übertragung (HTTPS), optional mit HTTP/2, HTTP/3 oder VPN.
  2. API-Authentisierung: Wahl geeigneter Mechanismen (Basic Auth, API-Key, OAuth 2.0), abhängig von der Komplexität und den Sicherheitsanforderungen.
  3. Gezielte Autorisierung: Umsetzung von RBAC, ABAC oder einem anderen Feingranularen Modell, um zu bestimmen, wer welche Aktionen ausführen darf.

Durch die Kombination dieser Konzepte wird eine Defense-in-Depth Strategie verfolgt, bei der mehrere Schutzebenen für eine hohe Sicherheit sorgen. Jedes Projekt sollte die angemessenen Maßnahmen basierend auf Risikoabschätzung und regulatorischen Vorgaben auswählen und kontinuierlich überwachen (Monitoring, Logging, Auditing).

AVSW-Overview