Security-Hardening Runde 8: DNS-Rebinding + Per-File-Ownership
Loose Ends aus Runde 5/7 abgearbeitet.
🛡 DNS-Rebinding-Schutz in SSRF-Guard
- safeResolveHost() löst Hostname zu IPv4+IPv6 auf, prüft jede IP
gegen die Block-Liste, gibt {ip, servername} zurück.
- Caller (test-connection, test-mail-access) übergibt host=ip plus
servername=hostname an die Mail-Services. Damit kann ein zweiter
DNS-Lookup zur Connection-Zeit nicht plötzlich auf interne IPs
umlenken (rebound-Attack).
- ImapCredentials/SmtpCredentials um optionales servername-Feld
erweitert; Services nutzen es als TLS-SNI / Cert-Validation-Hint.
🔒 Per-File-Ownership-Check (DSGVO-Härtung)
- express.static('/api/uploads') ersetzt durch GET /api/files/download
mit Pfad→Resource→Owner-Mapping in fileDownload.service.ts.
- 12 subDir-Mappings (bank-cards, documents, contract-documents,
invoices, cancellation-*, authorizations, business-/commercial-/
privacy-, pdf-templates).
- canAccessCustomer / canAccessContract / Permission-Check je nach
Owner-Typ. Portal-User sieht jetzt nur eigene Dateien, selbst wenn
er fremde Filenames kennt.
- Backwards-Compat: /api/uploads/* bleibt als Shim erhalten, ruft
intern denselben Owner-Check.
- Frontend fileUrl() zeigt auf /api/files/download?path=...&token=...
Live-verifiziert:
- Eigene Datei: 200, random Pfad: 404, ../etc/passwd: 400, kein
Token: 401, Backwards-Compat-Shim: 200.
- DNS-Rebinding: nip.io-Hostname mit interner Target-IP wird via
DNS-Lookup geblockt; gmail.com (legitim) geht durch.
Bewusst nicht gemacht:
- Signierte URLs mit kurzlebigen Download-Tokens – v1.2-Item, da
invasiv für <a href>-Flows ohne JS.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -141,6 +141,39 @@ isolierte Instanz (keine Multi-Tenancy im Code), Provisioning + Abrechnung
|
||||
- Provider/Tariff-GETs: `requirePermission('providers:read')` (Portal-Kunden sehen Provider-Liste nicht mehr)
|
||||
- SMTP-Header-Injection: zentrale CRLF-Validierung in `smtpService.sendEmail` (schützt alle Caller)
|
||||
- bcrypt cost 10 → 12 (OWASP 2026)
|
||||
- **Runde 8 – Loose Ends (DNS-Rebinding + Per-File-Ownership):**
|
||||
- **DNS-Rebinding-Schutz** in test-connection / test-mail-access:
|
||||
Hostnames werden vor Connect via `dns.resolve4/6` aufgelöst und
|
||||
jede IP gegen die SSRF-Block-Liste geprüft. Connection läuft
|
||||
anschließend gegen die IP, der ursprüngliche Hostname als
|
||||
`tls.servername` für SNI/Cert-Validation. Ein zweiter DNS-Lookup
|
||||
kann keine geblockte IP unterschieben.
|
||||
- **Per-File-Ownership-Check** statt freiem static-Handler:
|
||||
`app.use('/api/uploads', authenticate, express.static)` wird
|
||||
ersetzt durch `GET /api/files/download?path=...`. Der
|
||||
Controller mappt den Pfad via DB-Lookup auf Customer/Contract
|
||||
und delegiert an `canAccessCustomer`/`canAccessContract` –
|
||||
ein eingeloggter Portal-Kunde kann jetzt nur seine eigenen
|
||||
(oder vertretene mit Vollmacht) Dateien laden, selbst wenn
|
||||
er fremde Filenames irgendwo mitgeschnitten hätte.
|
||||
`/api/uploads/*` bleibt als Backwards-Compat-Shim erhalten,
|
||||
ruft aber denselben Owner-Check.
|
||||
- 12 subDir-Mappings: bank-cards, documents, business-/commercial-/
|
||||
privacy-, authorizations, contract-documents, invoices, alle
|
||||
4 cancellation-* + pdf-templates (admin-only).
|
||||
- Frontend `fileUrl()` zeigt jetzt auf den neuen Endpoint.
|
||||
Path-Traversal wird sowohl per Format-Validation (begin /uploads/,
|
||||
no '..') als auch durch absoluten Path-Vergleich gegen uploadsRoot
|
||||
geblockt.
|
||||
- Live-verifiziert: Portal-User lädt eigene Contract-Datei (200),
|
||||
random Pfad (404), Traversal (400), kein Token (401), Backwards-
|
||||
Compat-Shim (200).
|
||||
|
||||
**Bewusst NICHT gemacht (für v1.2):**
|
||||
- Signierte URLs mit kurzlebigen Download-Tokens statt JWT-im-Query
|
||||
(verhindert Token-Leak via Logs/Referrer). Nicht trivial wegen
|
||||
<a href>-Downloads ohne JS, lassen wir bis später.
|
||||
|
||||
- **Runde 7 – Letzter Schliff (SSRF + Logout):**
|
||||
- **SSRF-Schutz** in `test-connection` und `test-mail-access`: ein
|
||||
Admin-User konnte über die Plesk-API-URL bzw. SMTP/IMAP-Server-Felder
|
||||
|
||||
Reference in New Issue
Block a user