Pentest 2026-05-28 LOW 34.5: Backend-Validierung für AppSettings

Schema-Whitelist und Trailing-Slash-Strip für portalLoginUrl standen
NUR im Frontend. Der API-Endpoint nahm sonst /relative/path,
javascript:/ftp:/data:-Schemata und private IPs ungeprüft entgegen –
das landet als toter / bösartiger Link in den an Kunden verschickten
Portal-Mails (Open-Redirect / SSRF-Vektor).

Neuer validateSettingValue(key, value) in appSetting.service mit
per-Key-Logik:
  - portalLoginUrl: absolute http(s)-URL, isBlockedSsrfHost-Check
    (Cloud-Metadata immer, private Ranges via SSRF_BLOCK_PRIVATE_IPS),
    Trailing-Slash-Strip.
  - Schwellenwerte (deadline*/documentExpiry*): positive Integer.
  - Bool-Settings: strict 'true'/'false'.
  - monitoringAlertEmail: RFC-5322-light gegen Header-Injection.
  - Andere Keys: kein Format-Check (Default).

Controller (updateSetting + updateSettings) rufen Validator nach
stripHtml; bei Fehler HTTP 400 mit klarer Message. Bulk-PUT
validiert ALLE Werte VOR dem ersten DB-Write – kein halb-committed
State bei einem ungültigen Eintrag.

Live-verifiziert auf dev: alle Test-Payloads aus dem Pentest
sauber abgelehnt, legitime Werte (https-URL, Trailing-Slash, Pfade)
korrekt akzeptiert + normalisiert.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-28 14:39:45 +02:00
parent 2d4e4cdcc7
commit 100147107c
3 changed files with 128 additions and 3 deletions
+24
View File
@@ -120,6 +120,30 @@ isolierte Instanz (keine Multi-Tenancy im Code), Provisioning + Abrechnung
- **Live-verifiziert**: 4867 Datensätze + 1 Datei in 13.2s
wiederhergestellt, Log-Modal zeigt den vollständigen Verlauf.
- [x] **🛡️ Pentest 2026-05-28 LOW 34.5: Backend-URL-Validierung für AppSettings**
- Schema-Whitelist + Trailing-Slash-Strip standen NUR im Frontend.
API-Endpoint akzeptierte sonst `/relative/path`, `javascript:`,
`ftp://`, `http://192.168.1.1` etc. → Open-Redirect / SSRF-Vektor
in den an Kunden verschickten Portal-Mails.
- Neuer `validateSettingValue(key, value)` in appSetting.service.ts
mit per-Key-Logik: portalLoginUrl → nur http(s), absoluter Host,
`isBlockedSsrfHost`-Check, Trailing-Slash-Strip. Schwellenwerte
(deadline*/documentExpiry*) → positive Integer. Bool-Settings
→ strict `true`/`false`. monitoringAlertEmail → RFC-5322-light.
- Controller (updateSetting + updateSettings) ruft Validator nach
der HTML-Strip-Sanitisierung; bei Fehler 400 mit aussagekräftiger
Message. Bulk-PUT validiert ALLE Werte bevor irgendwas gespeichert
wird (kein halb-committed-State bei einem ungültigen Eintrag).
- **Live-verifiziert** auf dev:
- `/evil/path` → 400 "muss absolute http(s)-URL sein"
- `javascript:alert(1)` → 400 (durch stripHtml zu blocked: → Validator: unzulässiges Schema)
- `ftp://evil.com` / `data:text/html` → 400
- `http://169.254.169.254` → 400 (Cloud-Metadata immer geblockt)
- `http://192.168.1.1` → 200 (on-prem-Default; mit SSRF_BLOCK_PRIVATE_IPS=true → 400)
- `https://crm.example.de/` → DB: `https://crm.example.de` (Slash gestrippt)
- `https://crm.example.de//abc/` → DB: `https://crm.example.de//abc`
(nur trailing slash; doppelte slashes mittendrin bleiben)
- [x] **🐛 Bugfix: Portal-Passwörter in Verträgen wurden mutiliert**
- Folgefehler aus Pentest 31.1 (Stored-XSS-Strip): die rekursive
`sanitizeContractBody`-Funktion lief auch über `portalPassword`.