secure-express-setup
Version:
Military-grade one-command security setup for Express.js applications
71 lines (56 loc) • 3.18 kB
JavaScript
// lib/headers.js
/**
* Sets explicit, configurable security HTTP headers.
* Use in addition to helmet when you need exact header values
* or want to guarantee header presence for tests.
*/
function setupHeaders(options = {}) {
const cfg = {
xFrameOptions: options.xFrameOptions || 'DENY', // X-Frame-Options
xContentTypeOptions: options.xContentTypeOptions || 'nosniff', // X-Content-Type-Options
referrerPolicy: options.referrerPolicy || 'strict-origin-when-cross-origin',
contentSecurityPolicy: options.contentSecurityPolicy || null, // string or null
strictTransportSecurity: options.strictTransportSecurity || { maxAge: 31536000, includeSubDomains: true, preload: true },
permissionsPolicy: options.permissionsPolicy || null, // e.g. "geolocation=(), microphone=()"
expectCt: options.expectCt || null, // e.g. 'max-age=86400, enforce'
crossOriginEmbedderPolicy: options.crossOriginEmbedderPolicy || 'require-corp',
crossOriginOpenerPolicy: options.crossOriginOpenerPolicy || 'same-origin',
crossOriginResourcePolicy: options.crossOriginResourcePolicy || 'same-origin'
};
return (req, res, next) => {
// X-Frame-Options
if (cfg.xFrameOptions) res.setHeader('X-Frame-Options', cfg.xFrameOptions);
// X-Content-Type-Options
if (cfg.xContentTypeOptions) res.setHeader('X-Content-Type-Options', cfg.xContentTypeOptions);
// Referrer-Policy
if (cfg.referrerPolicy) res.setHeader('Referrer-Policy', cfg.referrerPolicy);
// Strict-Transport-Security (HSTS) - only set on HTTPS in production ideally
if (cfg.strictTransportSecurity) {
const { maxAge = 31536000, includeSubDomains = true, preload = false } = cfg.strictTransportSecurity;
let hsts = `max-age=${maxAge}`;
if (includeSubDomains) hsts += '; includeSubDomains';
if (preload) hsts += '; preload';
res.setHeader('Strict-Transport-Security', hsts);
}
// Content-Security-Policy - remember this may need to be tailored for your app
if (cfg.contentSecurityPolicy) {
res.setHeader('Content-Security-Policy', cfg.contentSecurityPolicy);
}
// Permissions-Policy (formerly Feature-Policy)
if (cfg.permissionsPolicy) {
res.setHeader('Permissions-Policy', cfg.permissionsPolicy);
}
// Expect-CT (optional)
if (cfg.expectCt) res.setHeader('Expect-CT', cfg.expectCt);
// Cross-Origin-Embedder-Policy
if (cfg.crossOriginEmbedderPolicy) res.setHeader('Cross-Origin-Embedder-Policy', cfg.crossOriginEmbedderPolicy);
// Cross-Origin-Opener-Policy
if (cfg.crossOriginOpenerPolicy) res.setHeader('Cross-Origin-Opener-Policy', cfg.crossOriginOpenerPolicy);
// Cross-Origin-Resource-Policy
if (cfg.crossOriginResourcePolicy) res.setHeader('Cross-Origin-Resource-Policy', cfg.crossOriginResourcePolicy);
// Minimal protective header for clickjacking fallback (already set via X-Frame-Options above)
// Additional custom headers can be added here if required
next();
};
}
module.exports = setupHeaders;