Fix low-level security issues
Content-Security-Policy: add header with default-src 'self', unsafe-inline for styles (needed for JS-generated inline style attrs), and data: for embedded logo/signature images. JSON body limit: reduce from 10mb to 2mb (logo cap is 512KB base64). Session maxAge: now configurable via SESSION_MAX_AGE_HOURS env var (default 168h / 7 days). Documented in .env.example. Password strength: centralize validation in auth.js and raise the bar to 10+ characters with at least one letter and one non-letter. Applied consistently to all four password-setting paths (initial setup, login change-password, admin create user, admin edit user).
This commit is contained in:
+8
-2
@@ -25,12 +25,14 @@ if (!process.env.SESSION_SECRET && process.env.NODE_ENV === 'production') {
|
||||
const SESSION_SECRET = process.env.SESSION_SECRET ||
|
||||
(() => { console.warn('[warn] SESSION_SECRET not set — using random secret (sessions will reset on restart)'); return crypto.randomBytes(32).toString('hex'); })();
|
||||
|
||||
const SESSION_MAX_AGE_MS = (parseInt(process.env.SESSION_MAX_AGE_HOURS, 10) || 168) * 60 * 60 * 1000;
|
||||
|
||||
app.use(session({
|
||||
store: new SessionStore(db),
|
||||
secret: SESSION_SECRET,
|
||||
resave: false,
|
||||
saveUninitialized: false,
|
||||
cookie: { httpOnly: true, sameSite: 'strict', maxAge: 7 * 24 * 60 * 60 * 1000 }, // 7 days
|
||||
cookie: { httpOnly: true, sameSite: 'strict', maxAge: SESSION_MAX_AGE_MS },
|
||||
}));
|
||||
|
||||
// Security headers
|
||||
@@ -38,10 +40,14 @@ app.use((req, res, next) => {
|
||||
res.setHeader('X-Content-Type-Options', 'nosniff');
|
||||
res.setHeader('X-Frame-Options', 'DENY');
|
||||
res.setHeader('Referrer-Policy', 'same-origin');
|
||||
// style-src unsafe-inline: required for inline style= attrs in JS-generated HTML
|
||||
// img-src data: required for base64-embedded logos and signatures
|
||||
res.setHeader('Content-Security-Policy',
|
||||
"default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; object-src 'none'");
|
||||
next();
|
||||
});
|
||||
|
||||
app.use(express.json({ limit: '10mb' }));
|
||||
app.use(express.json({ limit: '2mb' }));
|
||||
app.use(express.static(path.join(__dirname, '../public')));
|
||||
|
||||
// ── Auth routes (public — no requireAuth) ─────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user