fix(security): trust proxy = 1 bei HTTPS_ENABLED – echte Client-IP statt Proxy-IP
Wenn der TLS-Reverse-Proxy (Nginx Proxy Manager) auf einer SEPARATEN Box läuft, kommt nicht von 127.0.0.1 → `trust proxy = 'loopback'` greift nicht → req.ip bleibt die NPM-IP statt der echten Client-IP. Folgen: - Rate-Limiter sieht alle Angriffe als von "einem" Client (= NPM) - Security-Monitor loggt Proxy-IP statt Angreifer-IP (Beweis im Audit-Log: "ACCESS_DENIED ... 172.0.2.12" für alle Versuche) - IDOR-Threshold-Detection (>5 in 5 min pro IP) triggert auf der NPM-IP und blockt damit alle legitimen User durch denselben Proxy Fix: bei HTTPS_ENABLED=true `trust proxy = 1` (vertraue genau einem Hop – den vorgelagerten TLS-Proxy). Bei HTTPS_ENABLED=false bleibt es bei `loopback` (keine Proxy-Annahme bei direkter http://ip:port-Nutzung). Voraussetzung für HTTPS_ENABLED=true: Backend ist nicht direkt aus dem Internet erreichbar, sonst könnte ein direkter Connect ein X-Forwarded-For faken und den Limiter umgehen. Bei NPM-Setup gewährleistet durch Docker-Network + nicht-veröffentlichten Backend-Port. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+18
-9
@@ -84,16 +84,25 @@ if (!process.env.ENCRYPTION_KEY || process.env.ENCRYPTION_KEY.length !== 64) {
|
||||
const app = express();
|
||||
const PORT = process.env.PORT || 3001;
|
||||
|
||||
// Hinter einem Reverse-Proxy (Nginx/Plesk) läuft der Server typisch auf localhost.
|
||||
// `trust proxy = 'loopback'` vertraut nur Connections von 127.0.0.1 / ::1
|
||||
// (= lokaler Reverse-Proxy). Damit kann ein Angreifer mit DIREKTEM Zugriff
|
||||
// auf das Backend nicht via X-Forwarded-For den Rate-Limiter umgehen,
|
||||
// während gleichzeitig der lokale Reverse-Proxy die echte Client-IP liefern darf.
|
||||
// Trust-Proxy-Konfiguration für `req.ip` und `X-Forwarded-For`.
|
||||
//
|
||||
// WICHTIG für Production: Backend nur auf 127.0.0.1 lauschen lassen
|
||||
// (LISTEN_ADDR=127.0.0.1) – sonst kann ein direkter Connect von außen
|
||||
// trotzdem als loopback gelten, falls das Routing das so durchstellt.
|
||||
app.set('trust proxy', 'loopback');
|
||||
// Zwei Szenarien:
|
||||
// 1) **HTTPS_ENABLED=true** (Produktion mit vorgelagertem TLS-Proxy auf
|
||||
// EIGENER Box, z.B. Nginx Proxy Manager): `trust proxy = 1` vertraut
|
||||
// genau einem Hop → req.ip = echter Client (nicht der Proxy).
|
||||
// Voraussetzung: Backend ist NICHT direkt aus dem Internet erreichbar,
|
||||
// sonst könnte ein Direkt-Connect X-Forwarded-For faken und den
|
||||
// Rate-Limiter / Security-Monitor umgehen. Bei NPM-Setup ist das
|
||||
// durch das Docker-Network + nicht-veröffentlichten Backend-Port
|
||||
// gewährleistet.
|
||||
// 2) **HTTPS_ENABLED=false** (lokales Dev oder direkter http://ip:port-
|
||||
// Zugriff): `loopback` reicht – kein vertrauenswürdiger Hop davor.
|
||||
//
|
||||
// Vor dem Fix stand das auf `'loopback'` was im Produktiv-NPM-Setup
|
||||
// IMMER die Proxy-IP statt der Client-IP lieferte → Rate-Limit und
|
||||
// IDOR-Threshold-Detection sahen alle Angriffe als von „einem" Client.
|
||||
const trustProxyValue = process.env.HTTPS_ENABLED === 'true' ? 1 : 'loopback';
|
||||
app.set('trust proxy', trustProxyValue);
|
||||
|
||||
// ==================== SECURITY MIDDLEWARE ====================
|
||||
|
||||
|
||||
Reference in New Issue
Block a user