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: {