fix(security #7,#8,#9): signed cookies, isAdmin tamper-proof, schema validation

#7 isAdmin trusted from unsigned cookie:
  - isAdmin is derived server-side from Emby Policy at login time
  - Cookie is now signed (HMAC) when COOKIE_SECRET env var is set;
    Express rejects tampered signatures (signedCookies returns false)
  - dashboard.js /user-downloads and /status now use requireAuth
    middleware (req.user) instead of re-parsing cookie directly

#8 cookie-parser used without signing secret:
  - cookieParser(COOKIE_SECRET) in index.js when env var is set
  - Hard-fails at startup in production if COOKIE_SECRET unset
  - Warns in development

#9 Cookie JSON parsed without schema validation:
  - parseSessionCookie() in auth.js and requireAuth.js both validate:
    id (non-empty string), name (non-empty string), isAdmin (boolean)
  - Invalid/tampered cookies return null / 401 respectively
This commit is contained in:
2026-05-16 16:20:37 +01:00
parent 1eadb30481
commit d8584d0511
4 changed files with 55 additions and 47 deletions

View File

@@ -58,7 +58,14 @@ const { startPoller, POLL_INTERVAL, POLLING_ENABLED } = require('./utils/poller'
const app = express();
const PORT = process.env.PORT || 3001;
app.use(cookieParser());
const cookieSecret = process.env.COOKIE_SECRET;
if (!cookieSecret && process.env.NODE_ENV === 'production') {
console.error('[Security] COOKIE_SECRET is not set in production — cookies are unsigned and can be tampered with!');
process.exit(1);
} else if (!cookieSecret) {
console.warn('[Security] COOKIE_SECRET is not set — using unsigned cookies (acceptable for development only)');
}
app.use(cookieParser(cookieSecret || undefined));
app.use(express.json());
app.use(express.static(path.join(__dirname, '../public')));