security: HTTPS-only-Header per HTTPS_ENABLED-Flag steuern
`upgrade-insecure-requests` (CSP) + HSTS sperrten den Browser bei direktem http://ip:port-Zugriff aus (ERR_SSL_PROTOCOL_ERROR auf den Vite-Assets, weil Browser sie via https laden wollte). Beide Header sind jetzt default OFF und werden nur gesetzt, wenn HTTPS_ENABLED=true – also sobald ein TLS-Reverse-Proxy (Caddy/Traefik/Nginx) vor OpenCRM steht. Lokale + non-TLS-Deployments laufen damit ohne Stolperfalle. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -52,6 +52,12 @@ LISTEN_ADDR=0.0.0.0 # In Docker = 0.0.0.0, in Bare-Metal-Production = 127
|
|||||||
# Beispiel: CORS_ORIGINS=https://crm.deine-domain.de
|
# Beispiel: CORS_ORIGINS=https://crm.deine-domain.de
|
||||||
# CORS_ORIGINS=
|
# CORS_ORIGINS=
|
||||||
|
|
||||||
|
# HTTPS-only-Header (HSTS + upgrade-insecure-requests) – NUR aktivieren, wenn
|
||||||
|
# wirklich ein TLS-Proxy (Caddy/Traefik/Nginx) vor OpenCRM steht. Sonst sperrt
|
||||||
|
# sich der Browser bei direktem http://ip:port-Zugriff selbst aus
|
||||||
|
# (ERR_SSL_PROTOCOL_ERROR auf den Assets).
|
||||||
|
HTTPS_ENABLED=false
|
||||||
|
|
||||||
# ============== ADMINER (DB-UI) ==============
|
# ============== ADMINER (DB-UI) ==============
|
||||||
# Theme-Auswahl. Verfügbare Designs im offiziellen adminer:latest Image:
|
# Theme-Auswahl. Verfügbare Designs im offiziellen adminer:latest Image:
|
||||||
# adminer-dark, brade, bueltge, dracula, esterka, flat, galkaev,
|
# adminer-dark, brade, bueltge, dracula, esterka, flat, galkaev,
|
||||||
|
|||||||
+15
-2
@@ -151,6 +151,13 @@ app.use((_req, res, next) => {
|
|||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// HTTPS-only-Header (HSTS + upgrade-insecure-requests) nur setzen, wenn
|
||||||
|
// wirklich TLS davor läuft – sonst sperrt sich die App auf direkt-via-IP-
|
||||||
|
// Deployments (Browser versucht /assets/* via https zu laden → SSL-Error).
|
||||||
|
// Aktivieren mit HTTPS_ENABLED=true in der .env, sobald ein TLS-Proxy
|
||||||
|
// (Caddy/Traefik/Nginx) vor OpenCRM steht.
|
||||||
|
const httpsEnabled = process.env.HTTPS_ENABLED === 'true';
|
||||||
|
|
||||||
app.use(
|
app.use(
|
||||||
helmet({
|
helmet({
|
||||||
contentSecurityPolicy: {
|
contentSecurityPolicy: {
|
||||||
@@ -166,10 +173,16 @@ app.use(
|
|||||||
'object-src': ["'none'"],
|
'object-src': ["'none'"],
|
||||||
'base-uri': ["'self'"],
|
'base-uri': ["'self'"],
|
||||||
'form-action': ["'self'"],
|
'form-action': ["'self'"],
|
||||||
'upgrade-insecure-requests': [], // wenn HTTPS verfügbar, dann erzwingen
|
// useDefaults bringt 'upgrade-insecure-requests' selbst mit – explizit
|
||||||
|
// auf null setzen entfernt es aus dem Header (helmet-API).
|
||||||
|
'upgrade-insecure-requests': httpsEnabled ? [] : null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// Cross-Origin-Resource-Policy: "same-site" für SPA mit gleicher Origin
|
// HSTS nur wenn echt TLS vorhanden – sonst sperrt sich der Browser
|
||||||
|
// dauerhaft aus, wenn die App direkt via http://ip:port erreichbar ist.
|
||||||
|
strictTransportSecurity: httpsEnabled
|
||||||
|
? { maxAge: 31536000, includeSubDomains: true }
|
||||||
|
: false,
|
||||||
crossOriginResourcePolicy: { policy: 'same-site' },
|
crossOriginResourcePolicy: { policy: 'same-site' },
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ services:
|
|||||||
PORT: 3001
|
PORT: 3001
|
||||||
LISTEN_ADDR: 0.0.0.0
|
LISTEN_ADDR: 0.0.0.0
|
||||||
CORS_ORIGINS: ${CORS_ORIGINS:-}
|
CORS_ORIGINS: ${CORS_ORIGINS:-}
|
||||||
|
HTTPS_ENABLED: ${HTTPS_ENABLED:-false}
|
||||||
RUN_SEED: ${RUN_SEED:-false}
|
RUN_SEED: ${RUN_SEED:-false}
|
||||||
ports:
|
ports:
|
||||||
- "${OPENCRM_PORT:-3010}:3001"
|
- "${OPENCRM_PORT:-3010}:3001"
|
||||||
|
|||||||
Reference in New Issue
Block a user