diff --git a/backend/src/index.ts b/backend/src/index.ts index b37975d9..c1d3e8eb 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -81,11 +81,40 @@ app.set('trust proxy', 'loopback'); // ==================== SECURITY MIDDLEWARE ==================== -// HTTP Security Headers (X-Frame-Options, X-Content-Type-Options, HSTS, etc.) +// HTTP Security Headers (X-Frame-Options, X-Content-Type-Options, HSTS, CSP, ...) +// +// CSP ist konservativ aber SPA-tauglich: +// - script-src 'self' → keine externen Skripte, keine inline-Scripts +// (Vite baut Module-Skripte zu separaten Files, +// die sind 'self') +// - style-src 'self' 'unsafe-inline' → Tailwind/inline-Styles brauchen das +// (sicheres Trade-off; XSS via CSS ist +// marginal vs Lock-Out gegen die UI) +// - img-src self/data/blob → base64-Avatare + blob-URLs für PDFs/Downloads +// - font-src self/data → eingebettete Fonts +// - connect-src 'self' → API + WebSocket nur zur eigenen Origin +// - frame-ancestors 'none' → Clickjacking-Schutz (ersetzt X-Frame-Options) +// - object-src 'none' → keine Flash//-Embeds +// - base-uri 'self' → keine -Hijacking-Tricks +// - form-action 'self' → POST-Targets nur auf eigene Origin app.use( helmet({ - // CSP ausschalten – wird bei SPA schwierig, frontend setzt eigene CSP via meta - contentSecurityPolicy: false, + contentSecurityPolicy: { + useDefaults: true, + directives: { + 'default-src': ["'self'"], + 'script-src': ["'self'"], + 'style-src': ["'self'", "'unsafe-inline'"], + 'img-src': ["'self'", 'data:', 'blob:'], + 'font-src': ["'self'", 'data:'], + 'connect-src': ["'self'"], + 'frame-ancestors': ["'none'"], + 'object-src': ["'none'"], + 'base-uri': ["'self'"], + 'form-action': ["'self'"], + 'upgrade-insecure-requests': [], // wenn HTTPS verfügbar, dann erzwingen + }, + }, // Cross-Origin-Resource-Policy: "same-site" für SPA mit gleicher Origin crossOriginResourcePolicy: { policy: 'same-site' }, }),