security: Permissions-Policy-Header setzen (Pentest-Finding)
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) <noreply@anthropic.com>
This commit is contained in:
@@ -97,6 +97,45 @@ app.set('trust proxy', 'loopback');
|
|||||||
// - object-src 'none' → keine Flash/<object>/<embed>-Embeds
|
// - object-src 'none' → keine Flash/<object>/<embed>-Embeds
|
||||||
// - base-uri 'self' → keine <base>-Hijacking-Tricks
|
// - base-uri 'self' → keine <base>-Hijacking-Tricks
|
||||||
// - form-action 'self' → POST-Targets nur auf eigene Origin
|
// - 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(
|
app.use(
|
||||||
helmet({
|
helmet({
|
||||||
contentSecurityPolicy: {
|
contentSecurityPolicy: {
|
||||||
|
|||||||
Reference in New Issue
Block a user