Zum Inhalt springen

Services, Wiki-Artikel, Blog-Beiträge und Glossar-Einträge durchsuchen

↑↓NavigierenEnterÖffnenESCSchließen

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. [1] OWASP API Security Top 10 2023 - OWASP Foundation
  2. [2] OWASP API Security Project - OWASP Foundation
  3. [3] OWASP Testing Guide v4.2 - OWASP Foundation
  4. [4] JWT Security Best Practices - Auth0
  5. [5] OAuth 2.0 Security Best Current Practice - IETF
  6. [6] GraphQL Security Overview - OWASP Foundation

Fragen zu diesem Thema?

Unsere Experten beraten Sie kostenlos und unverbindlich.

Erstberatung

Über den Autor

Chris Wojzechowski
Chris Wojzechowski

Geschäftsführender Gesellschafter

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)
IT-Grundschutz-Praktiker (TÜV) IT Risk Manager (DGI) § 8a BSIG Prüfverfahrenskompetenz Ausbilderprüfung (IHK)
Dieser Artikel wurde zuletzt am 08.03.2026 bearbeitet. Verantwortlich: Chris Wojzechowski, Geschäftsführender Gesellschafter bei AWARE7 GmbH. Lizenz: CC BY 4.0 — freie Nutzung mit Namensnennung: „AWARE7 GmbH, https://a7.de

Cookielose Analyse via Matomo (selbst gehostet, kein Tracking-Cookie). Datenschutzerklärung