API-Sicherheit: OWASP API Top 10, Authentifizierung, Testing und Best Practices
Umfassender Guide zu API-Sicherheit: OWASP API Security Top 10 (2023) vollständig erklärt mit Code-Beispielen, API-Authentifizierung (API Keys, JWT, OAuth 2.0, mTLS), Testmethodik für REST und GraphQL, Tool-Einsatz (Burp Suite, Postman, jwt_tool, Nuclei), API-Discovery und Security-Checkliste für Entwickler und Penetrationstester.
Inhaltsverzeichnis (8 Abschnitte)
APIs sind das Rückgrat moderner Software - und der am schnellsten wachsende Angriffsvektor. Während klassische Web-Applikationen oft gut abgesichert sind, führen APIs häufig sensitive Operationen direkt aus, haben weniger UI-Sicherheitsmechanismen und werden selten gründlich getestet. Laut OWASP sind die meisten kritischen Web-Application-Sicherheitsvorfälle 2023/2024 über APIs erfolgt. Dieser Artikel behandelt die vollständige OWASP API Security Top 10, Authentifizierungsverfahren, Testmethodik und den richtigen Tool-Einsatz.
OWASP API Security Top 10 (2023)
API1: Broken Object Level Authorization (BOLA/IDOR)
Häufigste und gefährlichste API-Schwachstelle:
Das Problem:
GET /api/orders/12345 → gibt Bestellung von User X zurück
GET /api/orders/12346 → gibt Bestellung von User Y zurück!
(Angreifer ändert nur die ID → fremde Daten)
Verwundbar (Node.js/Express):
app.get('/api/v1/users/:userId/orders', auth, (req, res) => {
const orders = db.query('SELECT * FROM orders WHERE user_id = ?', req.params.userId);
// FEHLER: prüft "ist User eingeloggt?", nicht "gehört diese Ressource dem User?"
res.json(orders);
});
Sicher (User aus Auth-Token, nicht aus URL):
app.get('/api/v1/orders', auth, (req, res) => {
// req.user.id kommt aus validiertem JWT
const orders = db.query('SELECT * FROM orders WHERE user_id = ?', req.user.id);
res.json(orders);
});
// Oder wenn URL-ID nötig: Ownership-Check!
app.get('/api/v1/orders/:orderId', auth, async (req, res) => {
const order = await db.getOrder(req.params.orderId);
if (!order || order.userId !== req.user.id) {
return res.status(404).json({ error: 'Not found' }); // 404, nicht 403!
}
res.json(order);
});
Sicher (Python/FastAPI):
@app.get("/api/orders/{order_id}")
async def get_order(order_id: int, current_user: User = Depends(get_current_user)):
order = db.query(Order).filter(
Order.id == order_id,
Order.user_id == current_user.id # Object-Level-Auth!
).first()
if not order:
raise HTTPException(status_code=404)
return order
Schutzprinzipien:
→ JEDER API-Endpunkt: Objekt-Eigentümerschaft prüfen
→ Lieber 404 als 403 (verhindert Enumeration)
→ UUID statt auto-increment IDs (kein Ersatz für Auth, aber reduziert Raten-Angriffe)
→ Zentrale Authorisierungsschicht (nicht verstreut in jedem Endpoint)
API2: Broken Authentication
Schwache oder fehlende Authentifizierung:
Häufige Probleme:
→ Kein Rate Limiting auf Login-Endpoint → Brute Force
→ Schwacher JWT-Secret ("secret123" oder leer)
→ JWT ohne Expiry-Datum (exp claim fehlt)
→ API-Key in URL statt Header (landet in Server-Logs!)
→ Refresh-Token nie invalidiert
→ JWT: Algorithm-None-Angriff (alg: "none")
Sicheres JWT (Node.js):
// Token erstellen
const token = jwt.sign(
{ userId: user.id, email: user.email },
process.env.JWT_SECRET, // Aus Environment, nicht hardcoded!
{
expiresIn: '15m', // Kurze Laufzeit für Access Token
issuer: 'api.firma.de',
audience: 'api.firma.de',
algorithm: 'RS256' // Asymmetrisch → besser als HS256!
}
);
// Token validieren
const decoded = jwt.verify(token, process.env.JWT_PUBLIC_KEY, {
issuer: 'api.firma.de',
audience: 'api.firma.de',
algorithms: ['RS256'], // Algorithmus explizit angeben!
// → Verhindert Algorithm Confusion Attack (alg: "none")
});
Sicheres JWT (Python):
payload = {
"sub": user.id,
"iat": datetime.utcnow(),
"exp": datetime.utcnow() + timedelta(minutes=15), # Kurz!
"jti": str(uuid4()), # Unique ID für Revocation
}
# Decode: NICHT algorithms="auto"!
jwt.decode(token, secret, algorithms=["HS256"])
API-Key-Management:
→ API-Keys: als Hash in DB speichern (wie Passwörter!)
→ In HTTP-Header (X-API-Key), NICHT in URL
→ Pro Service/Consumer eigener Key mit Scope-Einschränkung
→ Ablaufdatum + regelmäßige Rotation
→ Audit-Log: welcher Key hat was aufgerufen?
# Richtig:
Authorization: Bearer sk_live_abc123xyz
X-API-Key: sk_live_abc123xyz
# Falsch (landet in Logs, Proxys, Browser-History!):
GET /api/data?api_key=sk_live_abc123xyz
API3: Broken Object Property Level Authorization
Mass Assignment und Excessive Data Exposure (neu in OWASP 2023):
Mass Assignment (Over-Posting):
# User sendet:
PUT /api/users/me
{"name": "Alice", "role": "admin"} ← role sollte nicht updatebar sein!
{"name": "Alice", "balance": 99999} ← Kontoguthaben manipuliert?
// Verwundbar (Node.js):
app.patch('/api/v1/profile', auth, async (req, res) => {
await db.update('users', { id: req.user.id }, req.body);
// req.body: { "name": "Alice", "isAdmin": true }
// → User macht sich selbst zum Admin!
});
// Sicher: Whitelist erlaubter Felder
const { name, email, bio } = req.body;
await db.update('users', { id: req.user.id }, { name, email, bio });
// Oder mit Zod-Schema:
const UpdateProfileSchema = z.object({
name: z.string().min(1).max(100).optional(),
email: z.string().email().optional(),
bio: z.string().max(500).optional(),
// isAdmin NICHT in Schema → wird ignoriert!
});
const data = UpdateProfileSchema.parse(req.body);
# Sicher (Python/FastAPI mit Pydantic):
class UserUpdateRequest(BaseModel):
name: Optional[str]
email: Optional[str]
# role fehlt → kann nicht gesetzt werden!
Excessive Data Exposure:
# API gibt zu viele Felder zurück:
GET /api/users → gibt password_hash, internal_id, payment_token zurück!
# Sicher: Response-Model (FastAPI filtert automatisch):
class UserResponse(BaseModel):
id: UUID
name: str
email: str
# Kein password_hash, kein payment_token!
@app.get("/api/users/{user_id}", response_model=UserResponse)
async def get_user(user_id: UUID):
...
API4: Unrestricted Resource Consumption
Kein Rate Limiting → DoS, Kosten, Credential Stuffing:
Rate Limiting (Node.js/Express):
import rateLimit from 'express-rate-limit';
const generalLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 Minuten
max: 100, // 100 Requests pro Window
standardHeaders: true,
legacyHeaders: false,
message: { error: 'Too many requests, please try again later' }
});
const authLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 5, // Nur 5 Login-Versuche
skipSuccessfulRequests: true
});
app.use('/api/', generalLimiter);
app.use('/api/auth/login', authLimiter);
Rate Limiting (Python/FastAPI mit slowapi):
from slowapi import Limiter
from slowapi.util import get_remote_address
limiter = Limiter(key_func=get_remote_address)
@app.post("/api/auth/login")
@limiter.limit("5/minute;20/hour") # Brute-Force-Schutz
async def login(request: Request, credentials: LoginRequest):
...
Pagination erzwingen:
# FALSCH: GET /api/users → gibt alle 1.000.000 User zurück
# RICHTIG: Immer limit + offset / cursor!
@app.get("/api/users")
async def get_users(
page: int = 1,
limit: int = Query(default=20, le=100) # Max 100!
):
offset = (page - 1) * limit
return db.query(User).offset(offset).limit(limit).all()
File-Upload-Limits:
ALLOWED_TYPES = ['image/jpeg', 'image/png', 'application/pdf']
MAX_SIZE = 10 * 1024 * 1024 # 10MB
if file.content_type not in ALLOWED_TYPES:
raise HTTPException(400, "Ungültiger Dateityp")
if file.size > MAX_SIZE:
raise HTTPException(413, "Datei zu groß")
API5: Broken Function Level Authorization
Vertikale Privilegieskalation in APIs:
Typisches Muster:
GET /api/users → normale User-Liste (jeder darf)
DELETE /api/users/{id} → User löschen (nur Admin!)
// Verwundbar: kein Role-Check auf DELETE
app.delete('/api/v1/admin/users/:id', auth, async (req, res) => {
await db.deleteUser(req.params.id);
// FEHLER: kein is_admin-Check!
res.json({ deleted: true });
});
// Sicher: Separate Admin-Middleware
const requireAdmin = (req, res, next) => {
if (req.user.role !== 'admin') {
return res.status(403).json({ error: 'Forbidden' });
}
next();
};
app.delete('/api/v1/admin/users/:id', auth, requireAdmin, async (req, res) => {
await db.deleteUser(req.params.id);
res.json({ deleted: true });
});
Admin-Endpunkte absichern:
→ Komplett separates Prefix: /admin/* statt /api/*
→ Eigenes Auth-Middleware für /admin/*
→ Separate Authentifizierung (nicht gleicher JWT!)
→ IP-Whitelist für /admin/* (nur Büro-IPs/VPN)
HTTP-Methoden-Beschränkung:
@app.api_route("/api/users/{id}", methods=["GET"]) # Nur GET!
API6-10: Weitere kritische Risiken
API6: Unrestricted Access to Sensitive Business Flows
Schwachstelle: Business-Prozesse automatisiert missbrauchbar
→ Rate Limiting für Business-Logik (Bestellungen, Coupons, Gift-Cards)
→ CAPTCHA für öffentliche Formulare
→ Velocity Checking: 100 Coupons in 1 Minute?
→ Race-Condition-Schutz bei gleichzeitigen Requests (Gift-Card-Fraud)
API7: Server Side Request Forgery (SSRF)
→ URL-Parameter → interne Ressourcen abfragen (webhook=, callback=, url=, src=)
→ AWS Metadata-Endpoint 169.254.169.254 → IAM-Credentials!
SSRF-Schutz (Python):
BLOCKED_RANGES = [
ipaddress.ip_network("127.0.0.0/8"),
ipaddress.ip_network("10.0.0.0/8"),
ipaddress.ip_network("172.16.0.0/12"),
ipaddress.ip_network("192.168.0.0/16"),
ipaddress.ip_network("169.254.0.0/16"), # Link-Local (AWS Metadata!)
ipaddress.ip_network("::1/128"),
]
# ACHTUNG DNS-Rebinding: nach DNS-Auflösung kann sich die IP ändern!
# Lösung: alle HTTP-Anfragen durch Proxy der IP-Check macht
API8: Security Misconfiguration
→ CORS zu weit: Access-Control-Allow-Origin: * (für interne APIs!)
→ Fehler-Details in Produktion: Stack-Traces, SQL-Fehler
→ Debug-Modus (Flask DEBUG=True) in Produktion aktiv
→ Default-Credentials: MongoDB ohne Auth, Elasticsearch öffentlich
CORS richtig:
# Nur erlaubte Origins:
origins = ["https://app.company.com", "https://admin.company.com"]
# NICHT: origins = ["*"] ← Cookies/Auth-Header dann exponiert!
# NIEMALS in Express:
res.setHeader('Access-Control-Allow-Origin', '*'); // Wenn Credentials genutzt!
# Error Handling in Production:
@app.exception_handler(Exception)
async def global_exception_handler(request, exc):
logger.error(f"Unhandled exception: {exc}", exc_info=True)
return JSONResponse(status_code=500, content={"error": "Internal server error"})
API9: Improper Inventory Management
→ Undokumentierte Legacy-Endpoints (v1 noch aktiv obwohl v3 current)
→ Sandbox/Staging-Umgebungen mit echten Daten
→ Shadow APIs (APIs ohne Owner)
→ API-Inventarisierung: OpenAPI/Swagger für ALLE Endpoints erzwingen
→ API-Gateway als Single Entry Point
→ Versionierungs-Policy: /api/v1/ → /api/v2/ (v1 deprecated und deaktiviert!)
API10: Unsafe Consumption of APIs (Third-Party)
→ Blindes Vertrauen in externe API-Responses
→ Externe API kompromittiert → eigene App kompromittiert!
Schutz:
→ Validierung: externe API-Responses immer mit Pydantic/Zod validieren
→ Timeouts: externe Calls nie unbegrenzt (max. 10s)
→ Circuit Breaker: bei Fehlern → Fallback statt Cascade Failure
import httpx
async with httpx.AsyncClient(timeout=10.0) as client:
try:
response = await client.get("https://api.external.com/data")
response.raise_for_status()
data = ExternalApiResponse(**response.json()) # Validierung!
except (httpx.TimeoutException, httpx.HTTPStatusError) as e:
logger.error(f"External API error: {e}")
return fallback_response() # Circuit Breaker!
API-Authentifizierung - Vergleich
1. API Keys:
Verwendung: Server-to-Server, Entwickler-APIs
Sicherheit: Mittel (kein Ablauf, breite Rechte)
Sicher mit:
→ In Header (X-API-Key), NICHT in URL
→ Pro Service/Consumer eigener Key
→ Regelmäßige Rotation
→ Audit-Log: welcher Key hat was aufgerufen?
→ Als Hash in DB speichern (wie Passwörter)
Beispiel:
curl -H "X-API-Key: sk-..." https://api.firma.de/data
2. JWT (JSON Web Token):
Verwendung: Web/Mobile Apps, stateless Auth
Sicherheit: Hoch wenn richtig implementiert
Pitfalls:
→ Algorithm "none" Angriff: immer Algorithmus-Whitelist!
→ JWT-Secret in Umgebungsvariable (nie hardcoded)
→ Kurze Gültigkeitsdauer (15min für Access, 7d für Refresh)
→ Kein sensitiver Inhalt in Payload (Base64, nicht verschlüsselt!)
→ jti-Claim für Token-Revocation
3. OAuth 2.0 + OpenID Connect:
Verwendung: Third-party Auth, Delegation
Sicherheit: Hoch (Industriestandard)
Flows:
→ Authorization Code + PKCE: für Web/Mobile (PKCE code_challenge prüfen!)
→ Client Credentials: Server-to-Server
→ state-Parameter auf CSRF prüfen
→ NIEMALS: Implicit Flow (veraltet, unsicher)
4. mTLS (Mutual TLS):
Verwendung: Microservices, B2B-APIs
Sicherheit: Sehr hoch
→ Beide Seiten authentifizieren sich mit Zertifikat
→ Kein Bearer Token der gestohlen werden kann
→ Komplexer Setup, aber maximale Sicherheit
GraphQL-Sicherheit
GraphQL bringt eigene Sicherheitsherausforderungen:
1. Introspection deaktivieren (Produktion):
// Apollo Server
const server = new ApolloServer({
typeDefs, resolvers,
introspection: process.env.NODE_ENV !== 'production',
});
// → Angreifer sieht kein Schema-Dump
2. Query Depth Limit (DoS-Schutz):
import depthLimit from 'graphql-depth-limit';
const server = new ApolloServer({
validationRules: [depthLimit(5)], // Max 5 Ebenen
});
// Nested Query Bomb ohne Limit:
{ user { friends { friends { friends { name } } } } }
// → exponentiell teurer, DoS möglich!
3. Query Complexity Limit:
import { createComplexityLimitRule } from 'graphql-validation-complexity';
const ComplexityRule = createComplexityLimitRule(1000);
// → Schutz gegen "all users + all orders + all items" in einer Query
4. Batching-Limit:
// GraphQL erlaubt mehrere Queries in einem Request:
POST /graphql
[
{"query": "mutation { login(user: \"alice\", pw: \"Password1\") }"},
{"query": "mutation { login(user: \"alice\", pw: \"Password2\") }"}
]
// → 100 Login-Versuche in einem Request → Rate-Limit-Bypass!
const server = new ApolloServer({
allowBatchedHttpRequests: false,
// Oder: Limit auf 10 Queries per Batch
});
5. Authorization in Resolvern (NICHT im Schema!):
const resolvers = {
Query: {
adminData: (_, __, context) => {
if (!context.user?.isAdmin) {
throw new ForbiddenError('Unauthorized');
}
return db.getAdminData();
}
}
};
6. Field-Level Authorization testen:
query {
user(id: "alice") {
username # erlaubt
email # erlaubt
internalNotes # erlaubt? (sollte nicht!)
passwordHash # sollte nie zurückgegeben werden!
}
}
API-Discovery und Reconnaissance
API-Endpunkte finden (Testphase):
Passive Quellen:
→ Swagger/OpenAPI-Dokumentation: /swagger.json, /openapi.yaml, /api-docs
→ API-Blueprint: /api/v1, /api/v2 (häufige Pfade)
→ JavaScript-Bundle-Analyse:
Chrome DevTools → Network → Filter: XHR/Fetch → alle API-Aufrufe sehen
→ GitHub-Repository des Produkts (falls OSS): API-Routes direkt lesen
→ Mobile-App-Analyse: APK/IPA dekompilieren → API-Endpoints im Code
→ Postman-Sammlungen: viele Unternehmen veröffentlichen auf postman.com
(oft API-Keys in Requests enthalten!)
→ Wayback Machine: https://web.archive.org/web/*/api.target.com/*
(alte API-Versionen, vergessene Endpoints)
Directory Brute-Force:
# feroxbuster mit API-Wordlist:
feroxbuster -u https://api.target.com \
-w /usr/share/wordlists/SecLists/Discovery/Web-Content/api/api-endpoints.txt \
-x json \
-H "Accept: application/json"
# kiterunner (API-spezifisch):
kr scan https://api.target.com -w routes-large.kite
# ffuf:
ffuf -w api-wordlist.txt -u "https://api.target.com/FUZZ" \
-H "Content-Type: application/json" -fc 404
Swagger-UI-Schwachstellen:
→ /swagger-ui: manchmal in Production verfügbar (vergessene Debug-Route!)
→ Gibt vollständige API-Dokumentation ohne Auth-Anforderung preis
→ GraphQL-Introspection: gibt vollständiges Schema preis
OWASP API Top 10 Testing-Methodik
API1 - BOLA/IDOR Testing:
Systematic Testing:
→ Zwei Accounts erstellen (User A + User B)
→ Mit User-B-Token auf User-A-Ressourcen zugreifen
→ IDs iterieren: 1, 2, 3, ... 100 (Burp Intruder!)
→ UUID? Trotzdem testen: gelten fälschlich als "secure"
Burp Intruder BOLA-Test:
GET /api/v1/documents/§123§
Authorization: Bearer USER_B_TOKEN
Payloads: 1, 2, 3, ..., 1000
Grep: Response-Length != Error-Response-Length → Fund!
---
API2 - Authentication Testing:
□ JWT-Schwächen:
→ alg=none: Signatur entfernen → Token akzeptiert?
→ RS256→HS256: Key-Confusion-Angriff
→ Expired Token: abgelaufener Token noch gültig?
→ Token von anderem Service/User akzeptiert?
jwt_tool:
jwt_tool eyJhbGciOiJIUzI1NiJ9... -T # Tamper-Mode
jwt_tool TOKEN -C -d rockyou.txt # Crack-Mode (HMAC-Secret)
# online: jwt.io → Payload anschauen + Signatur prüfen
□ API-Key-Schwächen:
→ Key im URL? (wird in Server-Logs gespeichert!)
→ Rate-Limiting für API-Key? Brute-Force möglich?
□ OAuth2 PKCE:
→ PKCE code_challenge korrekt implementiert?
→ state-Parameter auf CSRF prüfen
---
API3 - Mass Assignment Testing:
Test:
GET /api/user/me
→ enthält Antwort interne Felder? (isAdmin, internalId, creditScore)
→ Zeigt Response Passwort-Hash oder API-Key?
PUT /api/user/me
{"username": "alice", "role": "admin"} → Rolle geändert?
---
API4 - Rate Limiting Testing:
□ Login-Endpoint: 1000 Requests ohne Lockout?
# Burp Intruder Pitchfork: Passwort-Wordlist
□ OTP/Reset-Token: kann per Brute Force erraten werden?
□ File-Upload: kein Größenlimit? (DoS: 10GB-Upload!)
□ teuer berechnete Endpoints: /api/report → Flooding?
Rate-Limit-Bypass versuchen:
→ X-Forwarded-For Header: IP rotieren
→ User-Agent rotieren
→ verschiedene API-Versionen: /api/v1 vs. /api/v2 separate Rate-Limits?
---
API5 - Function Level Authorization:
□ Admin-Endpoints ohne Admin-Rolle?
GET /api/admin/users → mit normalem User-Token?
DELETE /api/admin/users/123 → mit normalem User-Token?
□ HTTP-Methoden-Wechsel:
GET /api/users/123 → erlaubt
DELETE /api/users/123 → auch erlaubt? (mit normalem User!)
□ HTTP/2 vs HTTP/1.1: manchmal unterschiedliche Auth-Prüfung!
---
API7 - SSRF Testing:
→ Alle URL-Parameter auf SSRF testen: webhook=, callback=, url=, redirect=, src=
POST /api/screenshot {"url": "http://192.168.1.1/admin"}
POST /api/webhook {"url": "http://169.254.169.254/latest/meta-data/"}
# AWS Metadata-Endpoint → IAM-Credentials!
---
API8 - Security Misconfiguration:
□ CORS-Test:
curl -H "Origin: https://evil.com" \
-I https://api.target.com/api/data
# Wenn: Access-Control-Allow-Origin: https://evil.com
# → CORS Misconfiguration!
□ HTTP-Methoden: OPTIONS, TRACE, PUT ungewollt aktiv?
□ Debug-Endpoints: /api/debug, /api/healthcheck mit internen Infos?
□ Error-Messages: Stack-Traces in 500-Errors?
---
API9 - Inventory Management:
□ Alte API-Versionen aktiv? /api/v1 neben /api/v3?
→ v1 hat oft geringere Security-Standards
□ Debug-Versions: /api/beta, /api/internal, /api/dev?
□ Undokumentierte Endpoints (nur in altem Code)
---
API10 - Third-Party API Consumption:
→ Webhook-Empfänger: Validiert er, dass Payload vom erwarteten Absender stammt?
→ Third-Party-API-Response: wird ohne Validation verarbeitet?
GraphQL Security Testing
GraphQL-spezifische Tests:
Introspection (Informationsleck):
# Alle Types und Felder abfragen:
POST /graphql
{
"__schema": {
"types": {
"name": true,
"fields": {
"name": true,
"type": {"name": true}
}
}
}
}
# Gibt vollständiges API-Schema zurück - sollte in Production deaktiviert sein!
Batching-Angriffe:
POST /graphql
[
{"query": "mutation { login(user: \"alice\", pw: \"Password1\") }"},
{"query": "mutation { login(user: \"alice\", pw: \"Password2\") }"},
{"query": "mutation { login(user: \"alice\", pw: \"Password3\") }"}
]
# 100 Login-Versuche in einem Request → Rate-Limit-Bypass!
Nested Queries (DoS via Tiefe):
{
user {
friends {
friends {
friends {
friends { name } # 10 Ebenen tief → DoS!
}
}
}
}
}
Tools für GraphQL-Testing:
InQL (Burp Extension): GraphQL-spezifische Tests, Schema-Extraktion
graphql-cop: automatischer GraphQL-Security-Scan
graphql-voyager: Schema-Visualisierung
Altair GraphQL Client: manuelles Testing
Tooling-Stack für API-Pentests
Burp Suite Pro:
→ HTTP-Proxy für alle API-Requests
→ Intruder: BOLA-Tests, Brute-Force
→ Scanner: automatische Schwachstellen-Erkennung
→ Extensions: InQL (GraphQL), JWT Editor, AuthMatrix
Postman:
→ API-Dokumentation importieren (OpenAPI)
→ Pre-Request Scripts: Token-Rotation automatisieren
→ Test Scripts: Response-Validation nach jedem Request
→ Collection Runner: alle API-Endpoints in Sequenz testen
# Pre-Request Script (Token refresh):
pm.sendRequest({
url: pm.environment.get("AUTH_URL") + "/token",
method: "POST",
body: { mode: "raw", raw: JSON.stringify({
client_id: pm.environment.get("CLIENT_ID"),
client_secret: pm.environment.get("CLIENT_SECRET"),
grant_type: "client_credentials"
})}
}, (err, res) => {
pm.environment.set("ACCESS_TOKEN", res.json().access_token);
});
# Security-Test in Postman (IDOR-Check):
pm.test("IDOR: cannot access other user's resource", function () {
pm.response.to.have.status(404); # Oder 403, nie 200!
});
jwt_tool:
jwt_tool TOKEN -T # Tamper-Mode
jwt_tool TOKEN -C -d rockyou.txt # Crack-Mode
kiterunner:
kr scan https://api.target.com -w /path/to/routes.kite
Nuclei API Templates:
nuclei -u https://api.target.com \
-tags api,jwt,swagger,graphql \
-t nuclei-templates/
OWASP ZAP API-Scan:
zap-api-scan.py \
-t https://api.example.com/openapi.json \
-f openapi \
-r api-report.html
Continuous API Security (CI/CD):
# 42Crunch API Security Audit (GitHub Action):
- uses: 42Crunch/api-security-audit-action@v3
with:
api-token: ${{ secrets.API_SECURITY_TOKEN }}
# Bewertet OpenAPI-Spec auf Sicherheit: 0-100 Score
# Failing bei < 75 Score
API-Sicherheitstest-Checkliste
Authentifizierung:
□ Ist jeder Endpunkt authentifiziert? (kein versehentlicher öffentlicher Endpoint)
□ Brute Force Rate Limiting auf Auth-Endpoints?
□ JWT: kurze Laufzeit, sicherer Algorithmus (RS256), kein "alg: none"?
□ Tokens nach Logout invalidiert?
□ API-Keys in HTTP-Header, nicht in URL?
Autorisierung:
□ BOLA-Test: andere User-IDs in URL/Body testen
□ Admin-Endpunkte: ohne Admin-Rechte aufrufbar?
□ Mass Assignment: werden unerwartete Felder ignoriert?
□ Scope-Check: OAuth Scopes korrekt geprüft?
□ HTTP-Methoden-Beschränkung: GET vs. DELETE vs. PUT?
Input Validation:
□ SQL Injection auf alle Parameter?
□ NoSQL Injection (MongoDB: $where, $gt Operator)?
□ Schema-Validierung für alle Request Bodies?
□ Datei-Upload: Typ-Check, Größen-Limit, Malware-Scan?
Rate Limiting:
□ Rate Limiting auf ALLEN Endpunkten?
□ Pro-User statt nur per-IP?
□ Business-Logic-Rate-Limiting (Coupons, Bestellungen)?
□ Rate-Limit-Bypass-Vektoren getestet (X-Forwarded-For, User-Agent)?
Security Misconfiguration:
□ CORS korrekt konfiguriert (kein * wenn Credentials)?
□ HTTP Security Headers (Helmet.js)?
□ Fehlerdetails in Antwort ausgeblendet (kein Stack-Trace)?
□ Alte API-Versionen deaktiviert?
□ Swagger/OpenAPI Docs: in Prod deaktiviert oder auth-geschützt?
□ Debug-Endpoints deaktiviert?
OWASP API Top 10 Gesamtcheck:
□ API1: BOLA getestet (zwei Accounts, ID-Iteration)
□ API2: Auth-Bypass versucht (JWT alg:none, Key-Confusion)
□ API3: Mass Assignment getestet, Response-Felder geprüft
□ API4: Rate Limiting vorhanden und nicht bypassbar
□ API5: Privilegierte Endpoints geprüft
□ API6: Business-Logic-Flows auf Automation getestet
□ API7: SSRF getestet (alle URL-Parameter)
□ API8: CORS, Security Headers, Debug deaktiviert
□ API9: API-Inventar vollständig, alte Versionen deaktiviert
□ API10: Third-Party-Responses validiert, Timeouts gesetzt Quellen & Referenzen
- [1] OWASP API Security Top 10 2023 - OWASP Foundation
- [2] OWASP API Security Project - OWASP Foundation
- [3] OWASP Testing Guide v4.2 - OWASP Foundation
- [4] JWT Security Best Practices - Auth0
- [5] OAuth 2.0 Security Best Current Practice - IETF
- [6] GraphQL Security Overview - OWASP Foundation
Fragen zu diesem Thema?
Unsere Experten beraten Sie kostenlos und unverbindlich.
Über den Autor
Geschäftsführender Gesellschafter der AWARE7 GmbH mit langjähriger Expertise in Informationssicherheit, Penetrationstesting und IT-Risikomanagement. Absolvent des Masterstudiengangs Internet-Sicherheit an der Westfälischen Hochschule (if(is), Prof. Norbert Pohlmann). Bestseller-Autor im Wiley-VCH Verlag und Lehrbeauftragter der ASW-Akademie. Einschätzungen zu Cybersecurity und digitaler Souveränität erschienen u.a. in Welt am Sonntag, WDR, Deutschlandfunk und Handelsblatt.
10 Publikationen
- Einsatz von elektronischer Verschlüsselung - Hemmnisse für die Wirtschaft (2018)
- Kompass IT-Verschlüsselung - Orientierungshilfen für KMU (2018)
- IT Security Day 2025 - Live Hacking: KI in der Cybersicherheit (2025)
- Live Hacking - Credential Stuffing: Finanzrisiken jenseits Ransomware (2025)
- Keynote: Live Hacking Show - Ein Blick in die Welt der Cyberkriminalität (2025)
- Analyse von Angriffsflächen bei Shared-Hosting-Anbietern (2024)
- Gänsehaut garantiert: Die schaurigsten Funde aus dem Leben eines Pentesters (2022)
- IT Security Zertifizierungen — CISSP, T.I.S.P. & Co (Live-Webinar) (2023)
- Sicherheitsforum Online-Banking — Live Hacking (2021)
- Nipster im Netz und das Ende der Kreidezeit (2017)