# Ticket 002 - Komplettes Code- und Security-Review: Effigenix Backend

**Datum:** 2026-02-19
**Scope:** Gesamtes Backend (Security, Auth/AuthZ, API-Schutz, Secrets, Betriebssicherheit)
**Status:** Offen

---

## Kritisch

### K1 - Fehlende Autorisierung auf sensiblen User-Endpunkten (IDOR / Privilege Escalation)

**Betroffene Dateien:**
- `src/main/java/de/effigenix/infrastructure/usermanagement/web/controller/UserController.java:200`
- `src/main/java/de/effigenix/infrastructure/usermanagement/web/controller/UserController.java:250`
- `src/main/java/de/effigenix/infrastructure/usermanagement/web/controller/UserController.java:313`
- `src/main/java/de/effigenix/infrastructure/usermanagement/web/controller/UserController.java:613`
- `src/main/java/de/effigenix/application/usermanagement/ListUsers.java:32`
- `src/main/java/de/effigenix/application/usermanagement/GetUser.java:25`
- `src/main/java/de/effigenix/application/usermanagement/UpdateUser.java:29`
- `src/main/java/de/effigenix/application/usermanagement/ChangePassword.java:36`

**Problem:**
Mehrere User-Endpunkte haben kein `@PreAuthorize`, und die zugehörigen Use Cases prüfen weder Berechtigungen noch Ownership (`actorId` vs. Ziel-User) robust. Jeder authentifizierte Benutzer kann dadurch potenziell Benutzerdaten lesen und ändern.

**Empfohlene Maßnahme:**
- Auf allen betroffenen Endpunkten explizite Policy erzwingen (`USER_READ`, `USER_WRITE` oder Self-Service-Policy).
- Zusätzlich serverseitige Ownership-/Scope-Prüfung im Application Layer einbauen (Defense in Depth).
- Negative Security-Tests ergänzen (fremden User lesen/ändern, Passwortänderung für fremden User).

---

### K2 - Refresh-Token wird als Access-Token akzeptiert

**Betroffene Dateien:**
- `src/main/java/de/effigenix/infrastructure/security/JwtTokenProvider.java:113`
- `src/main/java/de/effigenix/infrastructure/security/JwtTokenProvider.java:127`
- `src/main/java/de/effigenix/infrastructure/security/JwtSessionManager.java:89`
- `src/main/java/de/effigenix/infrastructure/security/JwtAuthenticationFilter.java:73`

**Problem:**
Refresh-Tokens enthalten zwar `type=refresh`, bei Validierung und Request-Authentifizierung wird der Typ aber nicht geprüft. Dadurch können Refresh-Tokens als Bearer für API-Zugriffe missbraucht werden.

**Empfohlene Maßnahme:**
- Token-Typ verpflichtend validieren (`access` nur im Request-Auth-Filter, `refresh` nur im Refresh-Flow).
- Separate Validierungsmethoden einführen (`validateAccessToken`, `validateRefreshToken`).
- Security-Tests ergänzen: Refresh-Token gegen geschützte Endpunkte muss 401 liefern.

---

## Hoch

### H1 - Unsichere Default-Credentials und Secrets im Standardprofil

**Betroffene Dateien:**
- `src/main/resources/application.yml:6`
- `src/main/resources/application.yml:8`
- `src/main/resources/application.yml:26`
- `src/main/resources/application.yml:27`
- `src/main/resources/application.yml:31`
- `src/main/resources/db/changelog/changes/004-seed-admin-user.sql:3`
- `src/main/resources/db/changelog/changes/004-seed-admin-user.sql:12`
- `src/main/resources/db/changelog/changes/004-seed-admin-user.sql:26`

**Problem:**
Statische Defaults für DB-Credentials, Security-User, JWT-Secret und Seed-Admin-Passwort sind im produktionsnahen Pfad hinterlegt. Bei fehlender Überschreibung entsteht ein direktes Übernahmerisiko.

**Empfohlene Maßnahme:**
- Keine sicherheitsrelevanten Defaults im Standardprofil; App soll fail-fast starten, wenn Secrets fehlen.
- Seed-Admin ausschließlich über dediziertes Dev-/Bootstrap-Profil.
- Secret-Management über Vault/Kubernetes Secrets/CI Secret Store erzwingen.

---

### H2 - Masterdata-Read-Endpunkte ohne Permission-Check

**Betroffene Dateien:**
- `src/main/java/de/effigenix/infrastructure/masterdata/web/controller/ArticleController.java:95`
- `src/main/java/de/effigenix/infrastructure/masterdata/web/controller/ArticleController.java:121`
- `src/main/java/de/effigenix/infrastructure/masterdata/web/controller/CustomerController.java:99`
- `src/main/java/de/effigenix/infrastructure/masterdata/web/controller/CustomerController.java:125`
- `src/main/java/de/effigenix/infrastructure/masterdata/web/controller/SupplierController.java:90`
- `src/main/java/de/effigenix/infrastructure/masterdata/web/controller/SupplierController.java:113`
- `src/main/java/de/effigenix/infrastructure/masterdata/web/controller/ProductCategoryController.java:72`
- `src/main/resources/db/changelog/changes/008-add-masterdata-permissions.sql:1`

**Problem:**
`MASTERDATA_READ` ist im Rollenmodell vorhanden, wird auf mehreren GET-Endpunkten aber nicht erzwungen.

**Empfohlene Maßnahme:**
- Alle Read-Endpunkte mit `@PreAuthorize("hasAuthority('MASTERDATA_READ')")` absichern.
- Optional feiner aufteilen (`ARTICLE_READ`, `CUSTOMER_READ` etc.) für Least Privilege.
- Integrationstests für positive und negative Berechtigungsfälle ergänzen.

---

## Mittel

### M1 - Refresh-Flow funktional unvollständig (Session Lifecycle)

**Betroffene Datei:**
- `src/main/java/de/effigenix/infrastructure/security/JwtSessionManager.java:141`

**Problem:**
`refreshSession()` wirft `UnsupportedOperationException`. Der Endpoint ist öffentlich verfügbar, aber die Kernlogik fehlt.

**Empfohlene Maßnahme:**
- Vollständigen Refresh-Flow implementieren: Refresh-Token validieren, User laden, Status prüfen, neues Token-Paar ausstellen.
- Rotation/Family-Tracking oder wenigstens Single-Use-Refresh-Tokens einführen.

---

### M2 - Kein Brute-Force-Schutz auf Login

**Betroffene Datei:**
- `src/main/java/de/effigenix/application/usermanagement/AuthenticateUser.java:42`

**Problem:**
Keine Rate-Limits, kein Backoff, kein attempt-based Locking. Ermöglicht Credential-Stuffing und Passwort-Raten.

**Empfohlene Maßnahme:**
- IP- und Username-basiertes Rate-Limiting (z. B. Bucket4j).
- Temporärer Lockout oder exponentielles Backoff nach Fehlversuchen.
- Security-Monitoring/Alerting auf auffällige Login-Muster.

---

### M3 - Logout-Invalidierung nur in-memory, ohne Cleanup und ohne Cluster-Fähigkeit

**Betroffene Dateien:**
- `src/main/java/de/effigenix/infrastructure/security/JwtSessionManager.java:35`
- `src/main/java/de/effigenix/infrastructure/security/JwtSessionManager.java:162`

**Problem:**
Blacklist liegt nur im Prozessspeicher, ist nach Neustart weg und wächst ohne TTL/Cleanup.

**Empfohlene Maßnahme:**
- Redis-basierte Blacklist mit TTL bis Token-Ablauf einsetzen.
- Alternativ zentraler Session Store + revocable token ids (`jti`).
- Cleanup-Strategie und Betriebsmetriken einführen.

---

## Niedrig

### N1 - Falsches Audit-Event bei fehlgeschlagenem Passwortwechsel

**Betroffene Datei:**
- `src/main/java/de/effigenix/application/usermanagement/ChangePassword.java:53`

**Problem:**
Bei falschem `currentPassword` wird `PASSWORD_CHANGED` statt eines Failure-Events geloggt.

**Empfohlene Maßnahme:**
- Eigenes Event `PASSWORD_CHANGE_FAILED` verwenden.
- Audit-Event-Mapping für Erfolgs-/Fehlerpfade systematisch prüfen.

---

### N2 - Verbose Fehler-/Debug-Ausgabe im Standardprofil

**Betroffene Dateien:**
- `src/main/resources/application.yml:39`
- `src/main/resources/application.yml:46`
- `src/main/resources/application.yml:47`
- `src/main/resources/application.yml:48`

**Problem:**
`include-message: always` plus DEBUG für Security und SQL im Standardprofil erhöht Risiko für Informationsabfluss.

**Empfohlene Maßnahme:**
- Sichere Logging-Baseline für Produktivbetrieb (`INFO/WARN`, keine sensiblen Details).
- Fehlermeldungen für Clients generisch halten, Details nur serverseitig protokollieren.
- Profilabhängige Logging-Policies (`dev`, `test`, `prod`) trennen.

---

## Test-/Betriebsnotiz

### T1 - Security-Integrationstests in aktueller Umgebung nicht ausführbar

**Nachweis:**
- `target/surefire-reports/de.effigenix.infrastructure.usermanagement.web.UserControllerIntegrationTest.txt`
- `target/surefire-reports/de.effigenix.infrastructure.usermanagement.web.SecurityIntegrationTest.txt`
- `target/surefire-reports/de.effigenix.infrastructure.usermanagement.web.AuthControllerIntegrationTest.txt`

**Problem:**
Tests schlagen hier fehl, weil der Sandbox-Runner keinen lokalen Socket/Port für den Embedded Tomcat öffnen darf (`java.net.SocketException: Operation not permitted`).

**Empfohlene Maßnahme:**
- Security-ITs in CI/Umgebung mit erlaubtem Port-Binding ausführen.
- Alternativ `@WebMvcTest`-basierte Tests ohne echten Server ergänzen, um AuthZ-Regeln isoliert zu prüfen.
