Pentest R89: Provider-Adressfelder härten
R89.1 MEDIUM + R89.2 LOW: sanitizeNotes(…, 500) macht silent slice(0, 500) statt 400, und stripHtml lief vor dem Length- Check – `<script>…</script>` reduzierte auf "" → null in DB → vorheriger Wert silent überschrieben (R87.1-Pattern auf Adress-Feldern). Fix: validateProviderAddress() in sanitize.ts – Raw-Input, max 500 mit ApiError(400), Blacklist <, >, Tab + alle Control-Chars außer \n. CRLF → LF VOR dem Length-Check, damit Editoren mit \r\n-Line-Endings nicht doppelt zählen. Eingehängt in stripProviderStrings für contactAddress/cancellationAddress. R89.3/R89.4 (Quotes/\n) bewusst akzeptiert – Pentester selbst sagt "kein Risiko", sind in Adressen legitim. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -575,6 +575,45 @@ Single-Line-Patch in [`backend/src/controllers/contract.controller.ts`](../backe
|
||||
|
||||
---
|
||||
|
||||
## 🔒 Runde 89 – Provider-Adressfelder härten
|
||||
|
||||
**Findings (R89.1 MEDIUM + R89.2 LOW):**
|
||||
|
||||
Beim neuen Provider-Modal (`Kontakt + Kündigung`) wurden
|
||||
`contactAddress` und `cancellationAddress` über `sanitizeNotes(…, 500)`
|
||||
geleitet. Zwei Probleme:
|
||||
|
||||
- **R89.1**: `sanitizeNotes` macht `slice(0, 500)` statt 400 – 501+ Zeichen
|
||||
wurden silent auf 500 abgeschnitten und mit 200 OK gespeichert.
|
||||
- **R89.2**: stripHtml lief vor dem Length-Check – derselbe Bug wie R87.
|
||||
`<script>…</script>` → leerer String → `null` in der DB → vorheriger
|
||||
Wert ohne Fehlermeldung überschrieben.
|
||||
|
||||
**Fix:** Eigener `validateProviderAddress(raw, fieldLabel)` in
|
||||
[`backend/src/utils/sanitize.ts`](../backend/src/utils/sanitize.ts):
|
||||
|
||||
- Validiert den Raw-Input direkt – kein stripHtml davor.
|
||||
- Max 500 Zeichen → `ApiError(400, …)` mit klarer Meldung.
|
||||
- Zeichen-Blacklist `[\x00-\x09\x0B\x0C\x0E-\x1F\x7F<>]` – erlaubt ist
|
||||
nur LF (`\n`). HTML-Klammern (`<`, `>`), Tab, NUL, CR-allein, alle
|
||||
anderen Control-Chars → 400. Tab raus weil Header-Injection-Vektor
|
||||
für CSV-/Mail-Exporte und in einer Postadresse nie legitim.
|
||||
- CRLF → LF normalisiert **vor** dem Length-Check, damit ein Editor
|
||||
mit `\r\n`-Zeilenenden nicht jedes Newline doppelt zählt.
|
||||
- Leerer / nur-Whitespace Input → `null` (Feld zurücksetzen).
|
||||
|
||||
Eingehängt in `stripProviderStrings` für die zwei Adressfelder. Die
|
||||
übrigen fünf Kontakt-Felder (Email/Telefon/Fax) gehen weiter durch
|
||||
`isValidEmail` / `sanitizePhoneField` – die hat der Pentester explizit
|
||||
als sauber bestätigt (7/7 + 6/6 Angriffsvektoren geblockt).
|
||||
|
||||
**Bewusst nicht gefixt:** R89.3 (Anführungszeichen) und R89.4 (`\n`).
|
||||
Der Pentester selbst sagt "kein unmittelbares Risiko, React escaped
|
||||
korrekt". Quotes in `Anbieter "GmbH"` sind legitim, `\n` ist Teil
|
||||
einer mehrzeiligen Postadresse.
|
||||
|
||||
---
|
||||
|
||||
## 🧭 Wann ist „dicht" dicht?
|
||||
|
||||
100 % gibt es nicht. Erreicht ist:
|
||||
|
||||
@@ -97,6 +97,22 @@ isolierte Instanz (keine Multi-Tenancy im Code), Provisioning + Abrechnung
|
||||
|
||||
## ✅ Erledigt
|
||||
|
||||
- [x] **🔒 Pentest R89 – Provider-Adressfelder härten**
|
||||
- R89.1 (MEDIUM): `sanitizeNotes(…, 500)` macht silent `slice(0, 500)`
|
||||
statt 400 – 501+ Zeichen wurden auf 500 abgeschnitten und mit
|
||||
200 OK gespeichert.
|
||||
- R89.2 (LOW): `stripHtml` lief vor dem Length-Check – `<script>…</script>`
|
||||
reduzierte auf leeren String → `null` in der DB → vorheriger Wert
|
||||
silent überschrieben (R87.1-Pattern auf Adress-Feldern).
|
||||
- Fix: eigener `validateProviderAddress()` in `sanitize.ts`. Raw-Input,
|
||||
max 500 → `ApiError(400)`, Blacklist `<`, `>`, Tab, alle Control-
|
||||
Chars außer `\n`. CRLF → LF normalisiert vor Length-Check.
|
||||
Eingehängt in `stripProviderStrings`.
|
||||
- R89.3 (Quotes) + R89.4 (`\n`): bewusst nicht gefixt – Pentester
|
||||
bestätigt "kein unmittelbares Risiko", React escaped korrekt,
|
||||
sind legitime Bestandteile mehrzeiliger Postadressen.
|
||||
- Doku in `SECURITY-HARDENING.md § Runde 89`.
|
||||
|
||||
- [x] **🆕 Anbieter: Kontakt + Kündigung als Stammdaten**
|
||||
- Sieben neue optionale Felder am `Provider`-Modell: `contactEmail`,
|
||||
`contactPhone`, `contactFax`, `contactAddress`, `cancellationEmail`,
|
||||
|
||||
Reference in New Issue
Block a user