# ASVS-light – Checkliste für eigene Apps Angelehnt an OWASP ASVS, reduziert auf das, was bei kleinen selbst gebauten Apps (FastAPI, Express, React/Next) regelmäßig schiefgeht. Jeder Punkt ist prüfbar. Spalte „Beleg“ sagt, womit man ihn nachweist. Prioritäten: **K** = Kritisch (No-Go, wenn offen), **H** = Hoch, **M** = Mittel. ## 1. Authentifizierung | ID | Prio | Punkt | Beleg | |----|------|-------|-------| | A1 | K | Jede Route außer einer expliziten Public-Liste verlangt Login | Test „jede Route verlangt Auth“ (Routen aus OpenAPI/Router, Leerlauf-Sperre) | | A2 | K | Identität kommt aus geprüfter Quelle (Session, JWT mit Signaturprüfung, Proxy-Header nur mit Shared Secret) | Spoofing-Test: gefälschter Header ohne Secret → 401 | | A3 | K | App-Port ist nicht am Reverse-Proxy vorbei erreichbar (Compose: kein `ports:` oder nur `127.0.0.1:`) | `docker compose config`, `ss -tlnp`, Zugriff von anderem Host | | A4 | H | Session-Cookies: `HttpOnly`, `Secure`, `SameSite=Lax/Strict` | Test auf `Set-Cookie` | | A5 | H | Login/Token-Endpunkte haben Rate-Limit | Konfiguration + Test | | A6 | M | Logout invalidiert die Session serverseitig | Test | ## 2. Autorisierung | ID | Prio | Punkt | Beleg | |----|------|-------|-------| | B1 | K | Objektzugriff wird pro Objekt geprüft (kein IDOR): Nutzer B kann Objekt von A weder lesen noch ändern noch löschen | IDOR-Tests mit zwei Nutzern | | B2 | K | Listen-Endpunkte liefern nur erlaubte Objekte | Test: Liste von B enthält nichts von A | | B3 | H | Rollenmatrix ist dokumentiert und als Tests abgebildet | Skill `authz-idor-audit` | | B4 | H | Rechte werden serverseitig geprüft, nicht nur im UI versteckt | Test direkt gegen API | | B5 | M | Admin-Funktionen auf eigenen Routen mit eigener Prüfung | Code-Review | ## 3. Eingaben | ID | Prio | Punkt | Beleg | |----|------|-------|-------| | C1 | K | SQL ausschließlich parametrisiert / ORM, keine String-Verkettung | Semgrep-Regeln, Ruff S608 | | C2 | H | Alle Request-Bodies laufen durch Schemas mit „unbekannte Felder verboten“ (Pydantic `extra="forbid"`, zod `.strict()`) | Mass-Assignment-Test (`role`, `owner`, `leader` im Body → 422/400) | | C3 | H | Ungültige Eingaben → 4xx, nie 500 | Test ungültige Eingabe, Fuzzing (`make fuzz`) | | C4 | H | Kein `eval`/`exec`, kein `shell=True`, kein unsicheres Deserialisieren (`pickle`, `yaml.load`) | Semgrep, Bandit | | C5 | M | Datei-Uploads: Typ/Größe begrenzt, Pfad nicht vom Client bestimmt | Test | ## 4. Frontend | ID | Prio | Punkt | Beleg | |----|------|-------|-------| | D1 | H | Kein `dangerouslySetInnerHTML`/`innerHTML` mit nicht vertrauenswürdigen Daten | ESLint `react/no-danger`, Semgrep | | D2 | H | Keine Tokens/Secrets in `localStorage`/`sessionStorage` | Semgrep, Playwright-Test auf Web Storage | | D3 | M | Security-Header gesetzt (CSP, `X-Content-Type-Options`, `frame-ancestors`) | ZAP-Baseline (`make zap`) | | D4 | M | Keine Secrets im Frontend-Bundle (`NEXT_PUBLIC_*`, `VITE_*` prüfen) | gitleaks auf Build-Output | ## 5. Konfiguration | ID | Prio | Punkt | Beleg | |----|------|-------|-------| | E1 | K | Keine Secrets im Repo oder in der Git-Historie | gitleaks (Pre-Commit + CI) | | E2 | K | CORS: kein `*`, kein `origin: true` zusammen mit Credentials | CORS-Test, Semgrep | | E3 | H | Debug-Modus aus, API-Docs in Prod aus oder geschützt | Prod-Konfigurationstest | | E4 | H | Fehlerantworten ohne Stacktrace/Exception-Text | Test auf generische 500er | | E5 | H | TLS-Prüfung nie abgeschaltet (`verify=False`, `rejectUnauthorized:false`, `NODE_TLS_REJECT_UNAUTHORIZED=0`) | Semgrep | | E6 | M | Container läuft nicht als root, Image ohne High/Critical | `make container` (Trivy, hadolint) | ## 6. Abhängigkeiten | ID | Prio | Punkt | Beleg | |----|------|-------|-------| | F1 | K | Keine High/Critical-Lücken ohne dokumentierte Ausnahme | `make audit` | | F2 | H | Jede neue Dependency vorher geprüft (existiert, nicht typosquat, gepflegt) | Skill `dependency-vetting`, `make vet-deps` | | F3 | M | Lockfile im Repo (`package-lock.json`, `requirements*.txt` gepinnt) | Repo | ## 7. Datenschutz | ID | Prio | Punkt | Beleg | |----|------|-------|-------| | G1 | H | Gesundheitsdaten (z. B. Abwesenheitsgrund „krank“) nur speichern, wenn nötig; sonst neutrale Abwesenheit | Datenmodell | | G2 | H | Logs ohne personenbezogene Daten, Tokens, Passwörter | Code-Review, Log-Stichprobe | | G3 | M | Testdaten synthetisch, keine echten Mitarbeiter-/Kundendaten in Tests, Fixtures, Seeds | Review | | G4 | M | Löschkonzept: wer löscht wann welche Personendaten | Doku |