openvibers/openvibe.media Commits

Object explorer (/me): never framed by another site (X-Frame-Options DENY, frame-ancestors 'none'); no x-powered-by on any answer (#142)

OP OpenVibers committed 27 days ago · 9491aca73d · 3 files, +6 −0

Changes

ddiff --git a/server/index.js b/server/index.js
iindex 19f3d3f..f95af58 100644
---- a/server/index.js
++++ b/server/index.js
@@@ -70,6 +70,7 @@ const ready = (async () => {
}
const app = express();
++ app.disable('x-powered-by'); // the framework is nobody's business (it was in every answer)
// Only the local reverse proxy (nginx on this host) is trusted to say who the client is: req.ip is
// its X-Forwarded-For for loopback peers and the socket address for anyone else, so a direct caller
// cannot pick its own IP (views, rate limits). `true` trusted every peer's header.
ddiff --git a/server/me/routes.js b/server/me/routes.js
iindex c23e90d..625def7 100644
---- a/server/me/routes.js
++++ b/server/me/routes.js
@@@ -47,6 +47,9 @@ function privateHeaders(_req, res, next) {
res.set('Cache-Control', cache.htmlHeaders({ private: true }));
res.set('X-Robots-Tag', 'noindex, nofollow');
res.set('X-Content-Type-Options', 'nosniff');
++ // A person's own pages and the staff form are never framed by another site (clickjacking).
++ res.set('X-Frame-Options', 'DENY');
++ res.set('Content-Security-Policy', "frame-ancestors 'none'");
next();
}
ddiff --git a/test/me-explorer.test.js b/test/me-explorer.test.js
iindex 1cb6f6c..d42e546 100644
---- a/test/me-explorer.test.js
++++ b/test/me-explorer.test.js
@@@ -162,6 +162,8 @@ const http = require('http');
assert.ok(r.text.includes('href="/auth/login?next=%2Fme"'), 'the sign-in prompt comes back to /me');
assert.ok(r.text.includes('<meta name="robots" content="noindex, nofollow">'));
assert.ok(r.headers['x-robots-tag'].includes('noindex') && r.headers['cache-control'] === 'private, no-store');
++ assert.strictEqual(r.headers['x-frame-options'], 'DENY', 'never framed by another site');
++ assert.strictEqual(r.headers['content-security-policy'], "frame-ancestors 'none'");
assert.ok(!r.text.includes(anaReady[0]) && !r.text.includes('<table'), 'nothing of anyone is shown');
assert.ok(r.text.includes('navbar.js') && r.text.includes('"sessionUrl":"/auth/me"'), 'in the OpenVibe Frame');
console.log('✅ signed out: the API answers 401, /me is a sign-in prompt in the Frame');