diff --git a/backend/server.js b/backend/server.js index 1302033df..1056969e7 100644 --- a/backend/server.js +++ b/backend/server.js @@ -39,6 +39,27 @@ if ( const { CONTRACTS_VERSION, GI_VERSION } = process.env +const securityHeaders = { + // This is the most likely to break things now; it may need changing when sandboxing or federation is implemented. + // - Not setting media-src since Background.vue dynamically adds sound assets. + // - The localhost:3000 entries are for BrowserSync support. + 'Content-Security-Policy': "child-src 'none'; connect-src 'self' blob: http://localhost:3001 ws://localhost:3001; font-src 'self'; form-action 'self'; frame-ancestors 'none'; frame-src 'none'; img-src 'self' https://unpkg.com blob: data:; manifest-src 'self'; object-src 'none'; script-src 'unsafe-eval'; script-src-attr 'none'; script-src-elem 'self' 'unsafe-inline'; style-src 'self'; style-src-attr 'none'; style-src-elem 'self' 'unsafe-inline'; upgrade-insecure-requests; worker-src 'self'", + // Block embedding cross-origin resources that don't explicitly allow it. Disabled because it blocks emoji sheet rendering. + // 'Cross-Origin-Embedder-Policy': 'require-corp', + // Don't share context with potentially untrusted sites. + 'Cross-Origin-Opener-Policy': 'same-origin', + // Block hotlinking. + 'Cross-Origin-Resource-Policy': 'same-origin', + // List generated using https://www.permissionspolicy.com. + 'Permissions-Policy': 'accelerometer=(), ambient-light-sensor=(), autoplay=(), battery=(), camera=(), cross-origin-isolated=(self), display-capture=(), document-domain=(), encrypted-media=(), execution-while-not-rendered=(self), execution-while-out-of-viewport=(self), fullscreen=(self), geolocation=(), gyroscope=(), keyboard-map=(), magnetometer=(), microphone=(), midi=(), navigation-override=(self), payment=(), picture-in-picture=(), publickey-credentials-get=(), screen-wake-lock=(), sync-xhr=(), usb=(), web-share=(self), xr-spatial-tracking=(), clipboard-read=(), clipboard-write=(self), gamepad=(), speaker-selection=()', + // This tells the user agent under which circumstances to send a referrer header and what information it should contain. + // Setting it can be useful to prevent destination servers of links in GI from learning the exact URL (which can contain, e.g., a group) the user came from. + 'Referrer-Policy': 'strict-origin-when-cross-origin', + 'X-Content-Type-Options': 'nosniff', + // Block loading the page in a frame. + 'X-Frame-Options': 'DENY' +} + const hapi = new Hapi.Server({ // debug: false, // <- Hapi v16 was outputing too many unnecessary debug statements // // v17 doesn't seem to do this anymore so I've re-enabled the logging @@ -67,9 +88,13 @@ hapi.ext({ // but custom headers can be manually added using `.output.headers`. // See https://hapi.dev/module/boom/api/. if (typeof request.response.header === 'function') { - request.response.header('X-Frame-Options', 'deny') + for (const [name, value] of Object.entries(securityHeaders)) { + request.response.header(name, value) + } } else { - request.response.output.headers['X-Frame-Options'] = 'deny' + for (const [name, value] of Object.entries(securityHeaders)) { + request.response.output.headers[name] = value + } } } catch (err) { console.warn(chalk.yellow('[backend] Could not set X-Frame-Options header:', err.message)) diff --git a/frontend/assets/style/_misc.scss b/frontend/assets/style/_misc.scss index 8cafb5497..f28904e2a 100644 --- a/frontend/assets/style/_misc.scss +++ b/frontend/assets/style/_misc.scss @@ -3,10 +3,10 @@ ========================================================================== */ .browserupgrade { - margin: 0.2em 0; + display: none; background: #ccc; color: #000; - padding: 0.2em 0; + padding: 0.2em; } /* ========================================================================== diff --git a/frontend/index.html b/frontend/index.html index f89085275..3ff31d65d 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -16,7 +16,7 @@ logo -