API-Sicherheit
Schutz von APIs (Application Programming Interfaces) gegen Missbrauch, unbefugten Zugriff, Injection-Angriffe und Datenlecks. APIs sind moderne Angriffsfläche: OWASP API Security Top 10 listet die häufigsten Schwachstellen von Broken Object Level Authorization bis Rate Limiting.
API-Sicherheit ist in der modernen Softwareentwicklung zur eigenständigen Disziplin geworden. Während klassische Web-Security sich auf HTML-Seiten konzentrierte, kommunizieren heute 83% der Webanwendungen primär über APIs (Akamai State of the Internet 2024).
OWASP API Security Top 10
OWASP hat eine eigenständige Top-10-Liste für API-Sicherheit:
API1: Broken Object Level Authorization (BOLA/IDOR)
// Unsicher: Kein Eigentümer-Check
GET /api/orders/4891
// → Angreifer ändert ID: GET /api/orders/4892 → fremde Bestellung sichtbar
// Sicher:
app.get('/api/orders/:id', authenticate, async (req, res) => {
const order = await Order.findOne({
_id: req.params.id,
userId: req.user.id // Eigentümercheck!
});
if (!order) return res.status(404).send();
res.json(order);
});
API2: Broken Authentication
// Gefährlich: Schwacher JWT-Algorithmus
// Header: {"alg": "none", "typ": "JWT"}
// → "none" Algorithmus akzeptiert jeden Token ohne Signaturprüfung!
// Sicher: Algorithmus explizit angeben
const token = jwt.verify(req.headers.authorization, process.env.JWT_SECRET, {
algorithms: ['HS256'], // Nur HS256 akzeptieren!
expiresIn: '1h'
});
API3: Broken Object Property Level Authorization
// Unsicher: Mass Assignment
app.put('/api/user', authenticate, async (req, res) => {
await User.findByIdAndUpdate(req.user.id, req.body); // Angreifer setzt isAdmin: true!
});
// Sicher: Nur erlaubte Felder
const { name, email } = req.body;
await User.findByIdAndUpdate(req.user.id, { name, email }); // Kein isAdmin möglich
API4: Unrestricted Resource Consumption
Ohne Rate Limiting:
- Angreifer sendet 10.000 Anfragen/Sekunde
- API-Kosten explodieren (AWS Lambda, OpenAI API)
- DoS für andere Nutzer
- Brute-Force möglich
API5: Broken Function Level Authorization
// Unsicher: Admin-Endpoint ohne Admin-Check
app.delete('/api/admin/users/:id', authenticate, async (req, res) => {
await User.findByIdAndDelete(req.params.id); // Kein Admin-Check!
});
// Sicher:
app.delete('/api/admin/users/:id', authenticate, requireAdmin, async (req, res) => {
// requireAdmin-Middleware prüft req.user.role === 'admin'
await User.findByIdAndDelete(req.params.id);
});
API Authentication Best Practices
API Keys
Nicht geeignet für User-Auth:
- API Keys sind Shared Secrets
- Können nicht widerrufen werden ohne alle Clients zu updaten
- Kein Scoping (Granulare Berechtigungen schwierig)
Gut für: Server-zu-Server-Kommunikation, Service-Accounts
Best Practices:
- API Key im Header:
Authorization: Bearer sk_live_abc123... - NIEMALS in URL:
?api_key=abc123(landet in Logs!) - Separate Keys pro Umgebung (Dev/Staging/Prod)
- Rotation ermöglichen
OAuth 2.0 + OIDC
Modernes Framework für API-Autorisierung:
- Tokens (Access Token, Refresh Token)
- Scopes: Granulare Berechtigungen (
read:orders,write:orders) - Token-Expiry: kurze Lebensdauer (15min Access Token)
- Revocation: Token widerrufen bei Kompromittierung
PKCE für Single Page Apps (verhindert Authorization Code Interception):
- Code Verifier + Code Challenge
- Auch ohne Client Secret sicher
JWT-Sicherheit
// JWT Best Practices:
const token = jwt.sign(
{
userId: user.id,
role: user.role,
// NICHT: Passwort, sensible Daten (JWT ist base64-decodierbar!)
},
process.env.JWT_SECRET, // Aus Environment Variable, niemals hardcoded
{
expiresIn: '15m', // Kurze Lebensdauer
issuer: 'api.firma.de',
audience: 'api.firma.de',
algorithm: 'HS256' // Explizit angeben
}
);
// Validierung:
const decoded = jwt.verify(token, process.env.JWT_SECRET, {
algorithms: ['HS256'], // Kein 'none' erlaubt!
issuer: 'api.firma.de',
audience: 'api.firma.de'
});
API Rate Limiting
// Express Rate Limiter
const rateLimit = require('express-rate-limit');
const apiLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 Minuten
max: 100, // 100 Anfragen pro IP
message: 'Too many requests, please try again later.',
standardHeaders: true, // X-RateLimit-* Headers
legacyHeaders: false,
});
app.use('/api/', apiLimiter);
// Strenger für Authentifizierung:
const authLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 5, // Nur 5 Login-Versuche
skipSuccessfulRequests: true, // Nur fehlgeschlagene zählen
});
app.use('/api/auth/login', authLimiter);
API Security Testing
Für Penetrationstest oder DAST
Tools für API-Pentest:
| Tool | Verwendungszweck |
|---|---|
| Burp Suite Pro | Intercepting Proxy + Scanner + Repeater |
| Postman | Manuelle Tests, Collection Runs |
| OWASP ZAP | Automatischer API-Scan |
| Arjun | Parameter-Discovery |
| ffuf | Endpoint-Fuzzing |
Wichtige Tests:
- IDOR: Alle IDs durchprobieren (1, 2, 3, …)
- Auth-Bypass: Token weglassen, alten Token, fremden Token
- Method Tampering: GET statt POST, HEAD statt GET
- Verbose Error Messages: Gibt API Stack Traces zurück?
- Mass Assignment: Extra-Felder im Request-Body senden
API Security Headers
# Empfohlene Headers für APIs:
add_header X-Content-Type-Options "nosniff";
add_header X-Frame-Options "DENY";
add_header Referrer-Policy "no-referrer";
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()";
# CORS richtig konfigurieren:
# NICHT: Access-Control-Allow-Origin: *
# Stattdessen:
Access-Control-Allow-Origin: https://app.firma.de
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Authorization, Content-Type