From d206b360a658c424daa74a7796ac5df0e2015739 Mon Sep 17 00:00:00 2001 From: duffyduck Date: Tue, 5 May 2026 15:25:27 +0200 Subject: [PATCH] security: Permissions-Policy-Header setzen (Pentest-Finding) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Helmet setzt Permissions-Policy nicht out-of-the-box. Eigene Middleware, die alle nicht benötigten Browser-APIs deaktiviert: camera, microphone, geolocation, payment, usb, midi, hid, accelerometer, gyroscope, magnetometer, ambient-light-sensor, battery, idle-detection, encrypted-media, picture-in-picture, publickey-credentials-get, screen-wake-lock, xr-spatial-tracking, web-share, autoplay, display-capture, sync-xhr, clipboard-read, cross-origin-isolated → alle =() Erlaubt für 'self': clipboard-write (CopyButton-Komponenten) fullscreen (falls Vorschau in Vollbild geöffnet wird) Damit hat eingeschleustes JS keinen Zugriff auf sensible Browser-APIs, selbst wenn XSS irgendwie durchrutschen sollte. Live-verifiziert: Header gesetzt + sauber formatiert. Co-Authored-By: Claude Opus 4.7 (1M context) --- backend/src/index.ts | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/backend/src/index.ts b/backend/src/index.ts index c1d3e8eb..295a9cc4 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -97,6 +97,45 @@ app.set('trust proxy', 'loopback'); // - object-src 'none' → keine Flash//-Embeds // - base-uri 'self' → keine -Hijacking-Tricks // - form-action 'self' → POST-Targets nur auf eigene Origin +// Permissions-Policy: schaltet Browser-APIs aus, die wir nicht brauchen. +// Verhindert, dass eingeschleustes JS Zugriff auf Kamera/Mikro/GPS/Payment etc. +// bekommt. clipboard-write ist 'self' für die CopyButton-Komponenten, +// fullscreen 'self' falls jemand mal eine Vorschau in Vollbild öffnet. +app.use((_req, res, next) => { + res.setHeader( + 'Permissions-Policy', + [ + 'accelerometer=()', + 'ambient-light-sensor=()', + 'autoplay=()', + 'battery=()', + 'camera=()', + 'clipboard-read=()', + 'clipboard-write=(self)', + 'cross-origin-isolated=()', + 'display-capture=()', + 'encrypted-media=()', + 'fullscreen=(self)', + 'geolocation=()', + 'gyroscope=()', + 'hid=()', + 'idle-detection=()', + 'magnetometer=()', + 'microphone=()', + 'midi=()', + 'payment=()', + 'picture-in-picture=()', + 'publickey-credentials-get=()', + 'screen-wake-lock=()', + 'sync-xhr=()', + 'usb=()', + 'web-share=()', + 'xr-spatial-tracking=()', + ].join(', '), + ); + next(); +}); + app.use( helmet({ contentSecurityPolicy: {