- Fixed unused function parameters by prefixing with underscore - Removed unused imports and variables - Applied eslint --fix for automatic style fixes - Property shorthand - String template literals - Prefer const over let where appropriate - Spacing and formatting Reduces lint errors from 108+ to 78 (61 unused vars, 17 other issues) Related to CI lint failures in previous commit 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
71 lines
2.2 KiB
JavaScript
71 lines
2.2 KiB
JavaScript
/**
|
|
* Security Headers Middleware (inst_044 - Quick Win Version)
|
|
* Implements comprehensive HTTP security headers
|
|
*
|
|
* QUICK WIN: Low effort, high value security improvement
|
|
* - Prevents XSS, clickjacking, MIME sniffing attacks
|
|
* - Enforces HTTPS, limits referrer leakage
|
|
* - Restricts dangerous browser features
|
|
*/
|
|
|
|
/**
|
|
* Apply security headers to all HTTP responses
|
|
*/
|
|
function securityHeadersMiddleware(req, res, next) {
|
|
// Content Security Policy (enforces inst_008 at HTTP level)
|
|
// Allows Tailwind inline styles, blocks inline scripts
|
|
res.setHeader(
|
|
'Content-Security-Policy',
|
|
[
|
|
"default-src 'self'",
|
|
"script-src 'self' https://cdn.jsdelivr.net", // Allow Chart.js CDN
|
|
"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com", // Tailwind + Google Fonts
|
|
"img-src 'self' data: https:",
|
|
"font-src 'self' https://fonts.gstatic.com https://cdnjs.cloudflare.com",
|
|
"connect-src 'self'",
|
|
"frame-ancestors 'none'",
|
|
"base-uri 'self'",
|
|
"form-action 'self'",
|
|
'upgrade-insecure-requests'
|
|
].join('; ')
|
|
);
|
|
|
|
// Prevent MIME type sniffing attacks
|
|
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
|
|
// Prevent clickjacking via iframes
|
|
res.setHeader('X-Frame-Options', 'DENY');
|
|
|
|
// Enable browser XSS filter (legacy browsers)
|
|
res.setHeader('X-XSS-Protection', '1; mode=block');
|
|
|
|
// Enforce HTTPS (HSTS) - only add if HTTPS is available
|
|
if (req.secure || req.get('x-forwarded-proto') === 'https') {
|
|
res.setHeader(
|
|
'Strict-Transport-Security',
|
|
'max-age=31536000; includeSubDomains' // 1 year
|
|
);
|
|
}
|
|
|
|
// Limit referrer information leakage
|
|
res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
|
|
|
|
// Restrict dangerous browser features
|
|
res.setHeader(
|
|
'Permissions-Policy',
|
|
'geolocation=(), microphone=(), camera=(), payment=()'
|
|
);
|
|
|
|
// Cache Control: NEVER cache admin files or API responses
|
|
if (req.path.startsWith('/admin/') ||
|
|
req.path.startsWith('/js/admin/') ||
|
|
req.path.startsWith('/api/')) {
|
|
res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
|
|
res.setHeader('Pragma', 'no-cache');
|
|
res.setHeader('Expires', '0');
|
|
}
|
|
|
|
next();
|
|
}
|
|
|
|
module.exports = { securityHeadersMiddleware };
|