36 lines
1.3 KiB
JavaScript
36 lines
1.3 KiB
JavaScript
'use strict';
|
|
|
|
/**
|
|
* Applies baseline security response headers on every request.
|
|
*
|
|
* CSP is intentionally omitted from this pass — Tailwind/shadcn inline styles,
|
|
* Vite build hashes, and Radix UI event handlers require a thorough audit before
|
|
* adding a restrictive policy. Deferred to a dedicated CSP hardening pass.
|
|
*/
|
|
function securityHeaders(req, res, next) {
|
|
// Prevent MIME-type sniffing (browsers must respect Content-Type)
|
|
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
|
|
// Disallow embedding in iframes from other origins — prevents clickjacking
|
|
res.setHeader('X-Frame-Options', 'SAMEORIGIN');
|
|
|
|
// Don't send full URL in Referer header to third-party origins
|
|
res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
|
|
|
|
// Disallow cross-domain policy files (Flash/PDF legacy attack surface)
|
|
res.setHeader('X-Permitted-Cross-Domain-Policies', 'none');
|
|
|
|
// Don't advertise the server tech stack
|
|
res.removeHeader('X-Powered-By');
|
|
|
|
// HSTS — only set when the app is explicitly configured to run over HTTPS.
|
|
// Setting this on HTTP breaks the site. Enable with HTTPS=true env var.
|
|
if (process.env.HTTPS === 'true') {
|
|
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
|
|
}
|
|
|
|
next();
|
|
}
|
|
|
|
module.exports = { securityHeaders };
|