Session Fixation Attack Vulnerabilities in Web Applications

High Risk Authentication & Authorization
session-managementsession-fixationauthenticationweb-securitysession-hijackinguser-sessionscsrfxss

What it is

A critical security vulnerability where an attacker can hijack user sessions by forcing users to use a predetermined session identifier. This occurs when applications fail to regenerate session IDs after authentication, allowing attackers to fix a session ID before user login and then gain access to the authenticated session. Session fixation attacks enable complete account takeover, unauthorized access to sensitive data, and privilege escalation.

// VULNERABLE: Complete session fixation vulnerability demonstration const express = require('express'); const session = require('express-session'); const app = express(); // VULNERABLE: Basic session configuration without security measures app.use(session({ secret: 'weak-secret', resave: false, saveUninitialized: true, name: 'sessionid', // Predictable name cookie: { secure: false, // Allows HTTP transmission httpOnly: false, // Accessible via JavaScript maxAge: null, // No expiration sameSite: false // No CSRF protection } })); app.use(express.json()); app.use(express.urlencoded({ extended: true })); // VULNERABLE: Accept session ID from multiple sources app.use((req, res, next) => { // VULNERABLE: Allow session ID from URL parameter if (req.query.sessionid) { req.sessionID = req.query.sessionid; console.log('Session ID set from URL:', req.sessionID); } // VULNERABLE: Allow session ID from custom header if (req.headers['x-session-id']) { req.sessionID = req.headers['x-session-id']; console.log('Session ID set from header:', req.sessionID); } next(); }); // VULNERABLE: Pre-login session setup that attackers can abuse app.get('/initialize-session', (req, res) => { // VULNERABLE: Creates session before authentication if (!req.session.initialized) { req.session.initialized = true; req.session.guestId = Math.random().toString(36); req.session.preferences = {}; } // VULNERABLE: Exposes session ID to client res.json({ message: 'Session initialized', sessionId: req.sessionID, guestId: req.session.guestId }); }); // VULNERABLE: Login endpoint without session regeneration app.post('/login', async (req, res) => { const { username, password } = req.body; try { // Mock authentication const user = await authenticateUser(username, password); if (user) { // VULNERABLE: No session regeneration - critical flaw! req.session.userId = user.id; req.session.username = user.username; req.session.role = user.role; req.session.isAuthenticated = true; req.session.loginTime = new Date(); // VULNERABLE: Preserves pre-login session data // This allows attackers to maintain their fixed session console.log('User logged in with existing session ID:', req.sessionID); res.json({ success: true, message: 'Login successful', sessionId: req.sessionID, // Exposing session ID user: { id: user.id, username: user.username, role: user.role } }); } else { res.status(401).json({ error: 'Invalid credentials' }); } } catch (error) { res.status(500).json({ error: 'Server error' }); } }); // VULNERABLE: Authentication middleware without proper validation function requireAuth(req, res, next) { if (req.session && req.session.isAuthenticated) { // VULNERABLE: No additional session security checks // No IP validation, no session age checks, etc. next(); } else { res.status(401).json({ error: 'Authentication required' }); } } // VULNERABLE: Session info endpoint that exposes too much app.get('/session-info', (req, res) => { res.json({ sessionId: req.sessionID, sessionData: req.session, cookies: req.headers.cookie, headers: req.headers }); }); // VULNERABLE: Protected endpoint using weak session validation app.get('/profile', requireAuth, (req, res) => { res.json({ userId: req.session.userId, username: req.session.username, role: req.session.role, sessionId: req.sessionID, // Still exposing session ID loginTime: req.session.loginTime }); }); // VULNERABLE: Session transfer endpoint (extremely dangerous) app.post('/transfer-session', (req, res) => { const { fromSessionId, toSessionId } = req.body; // VULNERABLE: Allows arbitrary session transfer if (req.sessionID === fromSessionId) { req.sessionID = toSessionId; res.json({ message: 'Session transferred', newSessionId: toSessionId }); } else { res.status(400).json({ error: 'Invalid session transfer' }); } }); // VULNERABLE: Logout without proper session cleanup app.post('/logout', requireAuth, (req, res) => { // VULNERABLE: Only marks as not authenticated, doesn't destroy session req.session.isAuthenticated = false; // Session data remains accessible res.json({ message: 'Logged out' }); }); // VULNERABLE: Admin endpoint to view all sessions (debugging feature) app.get('/admin/sessions', (req, res) => { // VULNERABLE: No authentication, exposes all session data const sessions = []; // In a real app, this would iterate through session store // This exposes all user sessions to anyone res.json({ sessions }); }); // Attack demonstration endpoints app.get('/attack-demo', (req, res) => { res.send(`

Session Fixation Attack Demo

Attacker can craft malicious links like:

After victim logs in with the fixed session, attacker can access:

`); }); app.listen(3000, () => { console.log('Vulnerable session fixation demo running on port 3000'); console.log('Visit /attack-demo to see attack examples'); });
// SECURE: Comprehensive session fixation protection implementation const express = require('express'); const session = require('express-session'); const RedisStore = require('connect-redis')(session); const redis = require('redis'); const crypto = require('crypto'); const helmet = require('helmet'); const rateLimit = require('express-rate-limit'); const winston = require('winston'); const app = express(); // Environment validation if (!process.env.SESSION_SECRET || process.env.SESSION_SECRET.length < 32) { console.error('SESSION_SECRET must be at least 32 characters long'); process.exit(1); } // Redis client for secure session storage const redisClient = redis.createClient({ url: process.env.REDIS_URL || 'redis://localhost:6379', password: process.env.REDIS_PASSWORD }); redisClient.on('error', (err) => { console.error('Redis Client Error', err); }); // Security middleware app.use(helmet({ contentSecurityPolicy: { directives: { defaultSrc: ["'self'"], scriptSrc: ["'self'"], styleSrc: ["'self'", "'unsafe-inline'"], connectSrc: ["'self'"] } } })); // Rate limiting const authLimiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: 5, // 5 login attempts message: { error: 'Too many login attempts' }, standardHeaders: true }); const sessionLimiter = rateLimit({ windowMs: 15 * 60 * 1000, max: 50, // 50 session operations message: { error: 'Too many session requests' } }); // Secure logger const logger = winston.createLogger({ level: 'info', format: winston.format.combine( winston.format.timestamp(), winston.format.json() ), transports: [ new winston.transports.File({ filename: 'security.log' }), new winston.transports.Console() ] }); // SECURE: Session configuration with maximum security app.use(session({ store: new RedisStore({ client: redisClient }), secret: process.env.SESSION_SECRET, name: process.env.SESSION_COOKIE_NAME || 'secure_app_session', resave: false, saveUninitialized: false, // SECURE: Don't create sessions for unauthenticated users rolling: true, // Reset expiration on activity cookie: { secure: process.env.NODE_ENV === 'production', // HTTPS only in production httpOnly: true, // SECURE: Prevent JavaScript access maxAge: 30 * 60 * 1000, // 30 minutes sameSite: 'strict' // SECURE: CSRF protection }, // SECURE: Cryptographically secure session ID generation genid: () => { return crypto.randomBytes(32).toString('hex'); } })); app.use(express.json({ limit: '10mb' })); app.use(express.urlencoded({ extended: true, limit: '10mb' })); // SECURE: Security middleware to prevent session fixation app.use((req, res, next) => { // SECURE: Reject session IDs from URL parameters if (req.query.sessionid || req.query.session_id) { logger.warn('Session fixation attempt detected', { ip: req.ip, userAgent: req.get('User-Agent'), query: req.query, timestamp: new Date().toISOString() }); return res.status(400).json({ error: 'Session ID cannot be provided via URL', code: 'SESSION_FIXATION_BLOCKED' }); } // SECURE: Reject session IDs from headers (except official cookie) if (req.headers['x-session-id'] || req.headers['session-id']) { logger.warn('Session fixation attempt via headers', { ip: req.ip, userAgent: req.get('User-Agent'), headers: { 'x-session-id': req.headers['x-session-id'], 'session-id': req.headers['session-id'] }, timestamp: new Date().toISOString() }); return res.status(400).json({ error: 'Session ID cannot be provided via headers', code: 'SESSION_FIXATION_BLOCKED' }); } next(); }); // SECURE: Session validation and security checks class SecureSessionManager { constructor() { this.maxConcurrentSessions = 5; this.sessionTimeout = 30 * 60 * 1000; // 30 minutes } // SECURE: Proper login with session regeneration async secureLogin(req, res) { const { username, password } = req.body; try { const user = await this.authenticateUser(username, password); if (!user) { logger.warn('Failed login attempt', { username, ip: req.ip, userAgent: req.get('User-Agent') }); return res.status(401).json({ error: 'Invalid credentials' }); } const oldSessionId = req.sessionID; // SECURE: Regenerate session ID after successful authentication req.session.regenerate((err) => { if (err) { logger.error('Session regeneration failed', { error: err.message, userId: user.id, ip: req.ip }); return res.status(500).json({ error: 'Session creation failed' }); } // Store user data in new session req.session.userId = user.id; req.session.username = user.username; req.session.role = user.role; req.session.isAuthenticated = true; // SECURE: Add security tracking data req.session.loginTime = new Date().toISOString(); req.session.ipAddress = this.getClientIp(req); req.session.userAgent = req.get('User-Agent'); req.session.securityLevel = this.calculateSecurityLevel(user); req.session.save((err) => { if (err) { logger.error('Session save failed', { error: err.message, userId: user.id }); return res.status(500).json({ error: 'Session save failed' }); } // SECURE: Log successful login with session regeneration logger.info('Secure login successful', { userId: user.id, username: user.username, oldSessionId: oldSessionId, newSessionId: req.sessionID, ipAddress: req.session.ipAddress, userAgent: req.session.userAgent }); res.json({ success: true, message: 'Login successful', user: { id: user.id, username: user.username, role: user.role }, expiresAt: new Date(Date.now() + this.sessionTimeout).toISOString() // SECURE: Never expose session ID in response }); }); }); } catch (error) { logger.error('Login error', { error: error.message, ip: req.ip }); res.status(500).json({ error: 'Internal server error' }); } } // SECURE: Comprehensive session validation validateSession(req, res, next) { if (!req.session || !req.session.isAuthenticated) { return res.status(401).json({ error: 'Authentication required', code: 'NOT_AUTHENTICATED' }); } // SECURE: Validate session integrity const currentIp = this.getClientIp(req); const currentUserAgent = req.get('User-Agent'); // IP address validation for high-security sessions if (req.session.securityLevel === 'high' && req.session.ipAddress !== currentIp) { logger.warn('Session IP mismatch detected', { userId: req.session.userId, sessionId: req.sessionID, originalIp: req.session.ipAddress, currentIp: currentIp }); this.destroySession(req, res, 'IP address mismatch detected'); return; } // User agent change detection if (req.session.userAgent !== currentUserAgent) { logger.warn('Session user agent change', { userId: req.session.userId, sessionId: req.sessionID, originalUserAgent: req.session.userAgent, currentUserAgent: currentUserAgent }); } // Session age validation const sessionAge = Date.now() - new Date(req.session.loginTime).getTime(); if (sessionAge > this.sessionTimeout) { this.destroySession(req, res, 'Session expired due to age'); return; } // Update last activity req.session.lastActivity = new Date().toISOString(); next(); } // SECURE: Complete session destruction destroySession(req, res, reason = 'Logout') { const userId = req.session?.userId; const sessionId = req.sessionID; req.session.destroy((err) => { if (err) { logger.error('Session destruction failed', { error: err.message, sessionId, userId }); return res.status(500).json({ error: 'Logout failed' }); } // SECURE: Clear session cookie res.clearCookie(process.env.SESSION_COOKIE_NAME || 'secure_app_session', { secure: process.env.NODE_ENV === 'production', httpOnly: true, sameSite: 'strict' }); logger.info('Session destroyed', { userId, sessionId, reason }); res.json({ message: 'Session terminated successfully', reason: reason }); }); } getClientIp(req) { return req.ip || req.headers['x-forwarded-for']?.split(',')[0] || req.connection.remoteAddress; } calculateSecurityLevel(user) { return user.role === 'admin' ? 'high' : 'normal'; } async authenticateUser(username, password) { // Implement secure authentication logic // This is a placeholder for actual authentication return { id: 1, username, role: 'user' }; } } const sessionManager = new SecureSessionManager(); // SECURE: No pre-login session initialization // Sessions are only created after successful authentication // SECURE: Login endpoint with proper protection app.post('/login', authLimiter, (req, res) => { sessionManager.secureLogin(req, res); }); // SECURE: Protected routes with comprehensive validation app.get('/profile', sessionManager.validateSession.bind(sessionManager), (req, res) => { res.json({ user: { id: req.session.userId, username: req.session.username, role: req.session.role }, sessionInfo: { loginTime: req.session.loginTime, lastActivity: req.session.lastActivity, securityLevel: req.session.securityLevel } // SECURE: Never expose session ID }); }); // SECURE: Session information with minimal exposure app.get('/session-status', sessionManager.validateSession.bind(sessionManager), (req, res) => { const sessionAge = Date.now() - new Date(req.session.loginTime).getTime(); const timeRemaining = sessionManager.sessionTimeout - sessionAge; res.json({ isAuthenticated: true, timeRemaining: Math.max(0, timeRemaining), securityLevel: req.session.securityLevel, lastActivity: req.session.lastActivity // SECURE: No sensitive session data exposed }); }); // SECURE: Proper logout with complete cleanup app.post('/logout', sessionManager.validateSession.bind(sessionManager), (req, res) => { sessionManager.destroySession(req, res, 'User logout'); }); // SECURE: Admin endpoints with proper authentication app.get('/admin/sessions', sessionManager.validateSession.bind(sessionManager), (req, res) => { // Only allow admin users if (req.session.role !== 'admin') { return res.status(403).json({ error: 'Admin access required' }); } // Return only non-sensitive session statistics res.json({ message: 'Session statistics would be available here', note: 'Individual session data is never exposed for security' }); } ); // SECURE: Security demonstration app.get('/security-info', (req, res) => { res.json({ security_features: [ 'Session ID regeneration after authentication', 'Cryptographically secure session ID generation', 'HttpOnly and Secure cookie flags', 'SameSite CSRF protection', 'IP address validation for high-security sessions', 'Session timeout enforcement', 'Comprehensive security logging', 'Protection against session fixation attacks' ], session_fixation_protection: [ 'Sessions only created after authentication', 'URL-based session ID injection blocked', 'Header-based session ID injection blocked', 'Session regeneration on every login', 'No session data preserved from pre-auth state' ] }); }); // Error handling app.use((error, req, res, next) => { logger.error('Unhandled error', { error: error.message, stack: error.stack, url: req.url, ip: req.ip }); res.status(500).json({ error: 'Internal server error' }); }); // Start server app.listen(3000, () => { logger.info('Secure session management server started', { port: 3000, environment: process.env.NODE_ENV || 'development' }); });

💡 Why This Fix Works

The vulnerable version demonstrates classic session fixation vulnerabilities: accepting session IDs from URLs and headers, not regenerating session IDs after authentication, exposing session IDs in responses, and maintaining pre-login session data. The secure version implements comprehensive protection including session ID regeneration after authentication, rejection of external session ID sources, secure cookie configuration, IP validation for high-security sessions, proper session cleanup, and comprehensive security logging.

Why it happens

The most common cause of session fixation vulnerabilities is when applications fail to regenerate session IDs after successful user authentication. This allows attackers to set a known session ID before the user logs in, and then use that same session ID to access the authenticated session.

Root causes

Missing Session ID Regeneration After Authentication

The most common cause of session fixation vulnerabilities is when applications fail to regenerate session IDs after successful user authentication. This allows attackers to set a known session ID before the user logs in, and then use that same session ID to access the authenticated session.

Preview example – JAVASCRIPT
// VULNERABLE: Express.js session handling without regeneration
const express = require('express');
const session = require('express-session');
const app = express();

app.use(session({
    secret: 'session-secret',
    resave: false,
    saveUninitialized: true,
    cookie: { secure: false, httpOnly: true }
}));

// VULNERABLE: Login without session regeneration
app.post('/login', async (req, res) => {
    const { username, password } = req.body;
    
    try {
        const user = await authenticateUser(username, password);
        
        if (user) {
            // VULNERABLE: Session ID remains the same after authentication
            req.session.userId = user.id;
            req.session.username = user.username;
            req.session.role = user.role;
            req.session.isAuthenticated = true;
            
            // No session.regenerate() call!
            console.log('User logged in with session ID:', req.sessionID);
            
            res.json({
                success: true,
                user: { id: user.id, username: user.username },
                sessionId: req.sessionID // Exposing session ID
            });
        } else {
            res.status(401).json({ error: 'Invalid credentials' });
        }
    } catch (error) {
        res.status(500).json({ error: 'Server error' });
    }
});

// VULNERABLE: Session verification without proper checks
function requireAuth(req, res, next) {
    if (req.session && req.session.isAuthenticated) {
        // No additional session validation
        next();
    } else {
        res.status(401).json({ error: 'Authentication required' });
    }
}

// Protected route using vulnerable session
app.get('/profile', requireAuth, (req, res) => {
    res.json({
        userId: req.session.userId,
        username: req.session.username,
        role: req.session.role
    });
});

Session ID Exposed in URLs or Accessible to Attackers

Session fixation attacks are facilitated when session IDs are transmitted through URLs, accept session IDs from GET parameters, or are accessible through client-side JavaScript. This allows attackers to craft malicious links or use XSS to set predetermined session IDs.

Preview example – JAVASCRIPT
// VULNERABLE: Multiple ways session IDs can be compromised
const express = require('express');
const app = express();

// VULNERABLE: Accepting session ID from URL parameters
app.use((req, res, next) => {
    // Accept session ID from query parameter
    if (req.query.sessionid) {
        req.sessionID = req.query.sessionid;
        console.log('Session ID from URL:', req.sessionID);
    }
    
    // Accept session ID from custom header
    if (req.headers['x-session-id']) {
        req.sessionID = req.headers['x-session-id'];
    }
    
    next();
});

// VULNERABLE: Session cookie not properly secured
app.use(session({
    secret: 'weak-secret',
    name: 'sessionid',
    resave: false,
    saveUninitialized: true,
    cookie: {
        secure: false,     // Allows transmission over HTTP
        httpOnly: false,   // Accessible via JavaScript
        sameSite: 'none',  // Allows cross-site requests
        maxAge: null       // No expiration
    }
}));

// VULNERABLE: Exposing session ID in response
app.get('/session-info', (req, res) => {
    res.json({
        sessionId: req.sessionID,      // Exposed in response
        sessionData: req.session,      // All session data exposed
        cookies: req.headers.cookie    // Cookie header exposed
    });
});

// VULNERABLE: Session ID in redirect URLs
app.post('/login', async (req, res) => {
    const { username, password } = req.body;
    
    if (await authenticateUser(username, password)) {
        req.session.userId = username;
        
        // VULNERABLE: Session ID in redirect URL
        res.redirect(`/dashboard?sessionid=${req.sessionID}`);
    } else {
        res.status(401).json({ error: 'Invalid credentials' });
    }
});

// VULNERABLE: Client-side session handling
app.get('/client-session.js', (req, res) => {
    res.type('application/javascript');
    res.send(`
        // VULNERABLE: Session management in client-side JavaScript
        window.sessionId = '${req.sessionID}';
        
        function setSessionId(newSessionId) {
            document.cookie = 'sessionid=' + newSessionId;
            window.sessionId = newSessionId;
        }
        
        function getSessionId() {
            return window.sessionId;
        }
        
        // VULNERABLE: Allow session ID manipulation
        if (window.location.hash.includes('sessionid=')) {
            const sessionId = window.location.hash.split('sessionid=')[1];
            setSessionId(sessionId);
        }
    `);
});

Predictable Session ID Generation

Applications using predictable session ID generation algorithms or weak random number generators make session fixation attacks easier. Attackers can predict or brute force session IDs, allowing them to pre-generate valid session identifiers.

Preview example – JAVASCRIPT
// VULNERABLE: Predictable session ID generation methods
const crypto = require('crypto');

class VulnerableSessionManager {
    constructor() {
        this.sessionCounter = 1000;
        this.startTime = Date.now();
    }
    
    // VULNERABLE: Sequential session IDs
    generateSequentialSessionId(userId) {
        return `session_${userId}_${this.sessionCounter++}`;
    }
    
    // VULNERABLE: Timestamp-based session IDs
    generateTimestampSessionId(userId) {
        const timestamp = Date.now();
        return `${userId}_${timestamp}`;
    }
    
    // VULNERABLE: Weak random session IDs
    generateWeakRandomSessionId() {
        // Using Math.random() - not cryptographically secure
        const randomNum = Math.floor(Math.random() * 1000000);
        return `session_${randomNum}`;
    }
    
    // VULNERABLE: MD5-based session IDs with predictable input
    generateMD5SessionId(userId) {
        const input = `${userId}_${Date.now()}_salt`;
        return crypto.createHash('md5').update(input).digest('hex');
    }
    
    // VULNERABLE: Short session IDs
    generateShortSessionId() {
        return Math.random().toString(36).substring(2, 8); // Only 6 characters
    }
    
    // VULNERABLE: Session ID with user input
    generateUserBasedSessionId(username) {
        // Using username in session ID generation
        const base = Buffer.from(username).toString('base64');
        const suffix = Math.floor(Math.random() * 1000);
        return `${base}_${suffix}`;
    }
}

// VULNERABLE: Using weak session manager in Express
const sessionManager = new VulnerableSessionManager();

app.post('/login', async (req, res) => {
    const { username, password } = req.body;
    
    if (await authenticateUser(username, password)) {
        // VULNERABLE: Using predictable session ID
        const sessionId = sessionManager.generateSequentialSessionId(username);
        
        // Store session data
        sessions.set(sessionId, {
            userId: username,
            createdAt: new Date(),
            lastAccess: new Date()
        });
        
        // Set predictable session cookie
        res.cookie('sessionid', sessionId, {
            httpOnly: false,  // Accessible via JavaScript
            secure: false     // Transmitted over HTTP
        });
        
        res.json({ success: true, sessionId: sessionId });
    } else {
        res.status(401).json({ error: 'Invalid credentials' });
    }
});

// VULNERABLE: Session validation without proper security
function validateSession(req, res, next) {
    const sessionId = req.cookies.sessionid || 
                     req.query.sessionid ||    // From URL
                     req.headers['x-session']; // From header
    
    if (!sessionId) {
        return res.status(401).json({ error: 'No session' });
    }
    
    const session = sessions.get(sessionId);
    
    if (session) {
        // No additional validation (IP, user agent, etc.)
        req.userId = session.userId;
        next();
    } else {
        res.status(401).json({ error: 'Invalid session' });
    }
}

Insufficient Session Invalidation and Timeout

Applications that fail to properly invalidate sessions on logout, don't implement session timeouts, or allow session reuse across different authentication contexts are vulnerable to session fixation. This allows attackers to maintain access even after apparent logout or extended periods of inactivity.

Preview example – JAVASCRIPT
// VULNERABLE: Inadequate session lifecycle management
const express = require('express');
const sessions = new Map(); // In-memory session store

class InsecureSessionManager {
    createSession(userId, userData) {
        const sessionId = this.generateSessionId();
        
        const session = {
            id: sessionId,
            userId: userId,
            userData: userData,
            createdAt: new Date(),
            lastActivity: new Date(),
            // No expiration time set
            isActive: true
        };
        
        sessions.set(sessionId, session);
        return sessionId;
    }
    
    // VULNERABLE: No proper session invalidation
    logout(sessionId) {
        const session = sessions.get(sessionId);
        
        if (session) {
            // VULNERABLE: Only marking as inactive, not deleting
            session.isActive = false;
            // Session data remains accessible
            console.log('User logged out, session marked inactive');
        }
    }
    
    // VULNERABLE: No session timeout enforcement
    validateSession(sessionId) {
        const session = sessions.get(sessionId);
        
        if (!session) {
            return null;
        }
        
        // VULNERABLE: No timeout check
        // No activity update
        // No IP/User-Agent validation
        
        return session.isActive ? session : null;
    }
    
    // VULNERABLE: Session reactivation without proper authentication
    reactivateSession(sessionId) {
        const session = sessions.get(sessionId);
        
        if (session) {
            // VULNERABLE: Can reactivate any session without authentication
            session.isActive = true;
            session.lastActivity = new Date();
            return session;
        }
        
        return null;
    }
    
    generateSessionId() {
        return Math.random().toString(36).substring(2);
    }
}

const sessionManager = new InsecureSessionManager();

// VULNERABLE: Login without proper session handling
app.post('/login', async (req, res) => {
    const { username, password } = req.body;
    
    if (await authenticateUser(username, password)) {
        const user = await getUserByUsername(username);
        
        // VULNERABLE: Create new session without invalidating old ones
        const sessionId = sessionManager.createSession(user.id, user);
        
        res.cookie('sessionid', sessionId);
        res.json({ success: true, sessionId });
    } else {
        res.status(401).json({ error: 'Invalid credentials' });
    }
});

// VULNERABLE: Logout that doesn't properly clean up
app.post('/logout', (req, res) => {
    const sessionId = req.cookies.sessionid;
    
    if (sessionId) {
        // VULNERABLE: Incomplete logout
        sessionManager.logout(sessionId);
        
        // Cookie not cleared properly
        res.cookie('sessionid', '', { maxAge: 1 }); // Weak cookie clearing
    }
    
    res.json({ message: 'Logged out' });
});

// VULNERABLE: Session reactivation endpoint
app.post('/reactivate-session', (req, res) => {
    const { sessionId } = req.body;
    
    // VULNERABLE: No authentication required for reactivation
    const session = sessionManager.reactivateSession(sessionId);
    
    if (session) {
        res.cookie('sessionid', sessionId);
        res.json({
            success: true,
            message: 'Session reactivated',
            user: session.userData
        });
    } else {
        res.status(404).json({ error: 'Session not found' });
    }
});

// VULNERABLE: Admin endpoint to view all sessions
app.get('/admin/sessions', (req, res) => {
    // VULNERABLE: No authentication, exposes all session data
    const allSessions = Array.from(sessions.entries()).map(([id, session]) => ({
        sessionId: id,
        userId: session.userId,
        userData: session.userData,
        createdAt: session.createdAt,
        isActive: session.isActive
    }));
    
    res.json(allSessions);
});

Fixes

1

Implement Proper Session Regeneration After Authentication

Always regenerate session IDs after successful authentication to prevent session fixation attacks. Implement secure session lifecycle management with proper invalidation of old sessions and creation of new cryptographically secure session identifiers.

View implementation – JAVASCRIPT
// SECURE: Proper session regeneration implementation
const express = require('express');
const session = require('express-session');
const RedisStore = require('connect-redis')(session);
const redis = require('redis');
const crypto = require('crypto');
const app = express();

// Redis client for session storage
const redisClient = redis.createClient({
    host: process.env.REDIS_HOST || 'localhost',
    port: process.env.REDIS_PORT || 6379,
    password: process.env.REDIS_PASSWORD
});

// SECURE: Session configuration with proper security settings
app.use(session({
    store: new RedisStore({ client: redisClient }),
    secret: process.env.SESSION_SECRET, // Strong secret from environment
    name: 'secure_session_id', // Non-default session name
    resave: false,
    saveUninitialized: false,
    rolling: true, // Reset expiration on activity
    cookie: {
        secure: process.env.NODE_ENV === 'production', // HTTPS only in production
        httpOnly: true,    // Prevent JavaScript access
        maxAge: 30 * 60 * 1000, // 30 minutes
        sameSite: 'strict' // CSRF protection
    },
    genid: () => {
        // SECURE: Cryptographically secure session ID generation
        return crypto.randomBytes(32).toString('hex');
    }
}));

class SecureSessionManager {
    // SECURE: Proper login with session regeneration
    async secureLogin(req, res) {
        const { username, password } = req.body;
        
        try {
            const user = await this.authenticateUser(username, password);
            
            if (!user) {
                return res.status(401).json({ error: 'Invalid credentials' });
            }
            
            // Get old session ID for logging
            const oldSessionId = req.sessionID;
            
            // SECURE: Regenerate session ID after successful authentication
            req.session.regenerate((err) => {
                if (err) {
                    console.error('Session regeneration failed:', err);
                    return res.status(500).json({ error: 'Session creation failed' });
                }
                
                // Store user data in new session
                req.session.userId = user.id;
                req.session.username = user.username;
                req.session.role = user.role;
                req.session.isAuthenticated = true;
                req.session.loginTime = new Date().toISOString();
                req.session.ipAddress = this.getClientIp(req);
                req.session.userAgent = req.get('User-Agent');
                
                // Save the session
                req.session.save((err) => {
                    if (err) {
                        console.error('Session save failed:', err);
                        return res.status(500).json({ error: 'Session save failed' });
                    }
                    
                    // Log session regeneration for security monitoring
                    this.logSessionEvent('login_session_regenerated', {
                        userId: user.id,
                        username: user.username,
                        oldSessionId: oldSessionId,
                        newSessionId: req.sessionID,
                        ipAddress: req.session.ipAddress,
                        userAgent: req.session.userAgent
                    });
                    
                    res.json({
                        success: true,
                        user: {
                            id: user.id,
                            username: user.username,
                            role: user.role
                        },
                        message: 'Login successful'
                        // Never expose session ID in response
                    });
                });
            });
        } catch (error) {
            console.error('Login error:', error);
            res.status(500).json({ error: 'Internal server error' });
        }
    }
    
    // SECURE: Session validation with security checks
    validateSession(req, res, next) {
        if (!req.session || !req.session.isAuthenticated) {
            return res.status(401).json({ error: 'Authentication required' });
        }
        
        // Validate session integrity
        const currentIp = this.getClientIp(req);
        const currentUserAgent = req.get('User-Agent');
        
        // IP address validation (configurable based on security requirements)
        if (process.env.VALIDATE_SESSION_IP === 'true' && 
            req.session.ipAddress !== currentIp) {
            
            this.logSessionEvent('session_ip_mismatch', {
                userId: req.session.userId,
                sessionId: req.sessionID,
                originalIp: req.session.ipAddress,
                currentIp: currentIp
            });
            
            // Destroy suspicious session
            req.session.destroy((err) => {
                if (err) console.error('Session destruction failed:', err);
            });
            
            return res.status(401).json({ 
                error: 'Session security violation',
                code: 'IP_MISMATCH'
            });
        }
        
        // User agent validation (less strict, log only)
        if (req.session.userAgent !== currentUserAgent) {
            this.logSessionEvent('session_useragent_change', {
                userId: req.session.userId,
                sessionId: req.sessionID,
                originalUserAgent: req.session.userAgent,
                currentUserAgent: currentUserAgent
            });
        }
        
        // Update last activity timestamp
        req.session.lastActivity = new Date().toISOString();
        
        next();
    }
    
    // SECURE: Proper logout with complete session cleanup
    async secureLogout(req, res) {
        const sessionId = req.sessionID;
        const userId = req.session?.userId;
        
        // Log logout event before destroying session
        if (userId) {
            this.logSessionEvent('logout', {
                userId: userId,
                sessionId: sessionId,
                duration: Date.now() - new Date(req.session.loginTime).getTime()
            });
        }
        
        // SECURE: Destroy session completely
        req.session.destroy((err) => {
            if (err) {
                console.error('Session destruction failed:', err);
                return res.status(500).json({ error: 'Logout failed' });
            }
            
            // Clear session cookie
            res.clearCookie('secure_session_id', {
                secure: process.env.NODE_ENV === 'production',
                httpOnly: true,
                sameSite: 'strict'
            });
            
            res.json({ message: 'Logged out successfully' });
        });
    }
    
    // SECURE: Force logout all sessions for a user
    async logoutAllSessions(userId) {
        try {
            // Get all sessions for user from Redis
            const keys = await redisClient.keys('sess:*');
            const sessions = await Promise.all(
                keys.map(key => redisClient.get(key))
            );
            
            const userSessions = sessions
                .filter(session => {
                    try {
                        const data = JSON.parse(session);
                        return data.userId === userId;
                    } catch {
                        return false;
                    }
                })
                .map(session => JSON.parse(session));
            
            // Delete all user sessions
            for (const session of userSessions) {
                const sessionKey = `sess:${session.sessionId}`;
                await redisClient.del(sessionKey);
            }
            
            this.logSessionEvent('logout_all_sessions', {
                userId: userId,
                sessionCount: userSessions.length
            });
            
            return userSessions.length;
        } catch (error) {
            console.error('Failed to logout all sessions:', error);
            throw error;
        }
    }
    
    getClientIp(req) {
        return req.ip || 
               req.headers['x-forwarded-for']?.split(',')[0] || 
               req.headers['x-real-ip'] || 
               req.connection.remoteAddress;
    }
    
    logSessionEvent(event, data) {
        const logEntry = {
            timestamp: new Date().toISOString(),
            event: event,
            data: data
        };
        
        // Log to secure audit system
        console.log('SESSION_AUDIT:', JSON.stringify(logEntry));
        
        // In production, send to security monitoring system
        // securityMonitor.log('session', logEntry);
    }
    
    async authenticateUser(username, password) {
        // Implement secure user authentication
        // This should include password hashing verification
        // Rate limiting, account lockout, etc.
        return null; // Placeholder
    }
}

const sessionManager = new SecureSessionManager();

// SECURE: Routes with proper session handling
app.post('/login', (req, res) => {
    sessionManager.secureLogin(req, res);
});

app.post('/logout', sessionManager.validateSession.bind(sessionManager), (req, res) => {
    sessionManager.secureLogout(req, res);
});

app.post('/logout-all-sessions', sessionManager.validateSession.bind(sessionManager), async (req, res) => {
    try {
        const count = await sessionManager.logoutAllSessions(req.session.userId);
        res.json({ 
            message: 'All sessions logged out successfully',
            sessionCount: count
        });
    } catch (error) {
        res.status(500).json({ error: 'Failed to logout all sessions' });
    }
});

app.get('/profile', sessionManager.validateSession.bind(sessionManager), (req, res) => {
    res.json({
        user: {
            id: req.session.userId,
            username: req.session.username,
            role: req.session.role
        },
        sessionInfo: {
            loginTime: req.session.loginTime,
            lastActivity: req.session.lastActivity
        }
    });
});
2

Secure Session Cookie Configuration and Transport

Implement secure session cookie settings to prevent session fixation through client-side manipulation. Use HTTPS-only cookies, HttpOnly flags, SameSite attributes, and proper cookie naming to prevent session ID exposure and manipulation.

View implementation – JAVASCRIPT
// SECURE: Comprehensive session cookie security configuration
const express = require('express');
const session = require('express-session');
const helmet = require('helmet');
const rateLimit = require('express-rate-limit');
const app = express();

// SECURE: Security headers and middleware
app.use(helmet({
    contentSecurityPolicy: {
        directives: {
            defaultSrc: ["'self'"],
            scriptSrc: ["'self'"],
            styleSrc: ["'self'", "'unsafe-inline'"],
            imgSrc: ["'self'", "data:"],
            connectSrc: ["'self'"],
            fontSrc: ["'self'"],
            objectSrc: ["'none'"],
            mediaSrc: ["'self'"],
            frameSrc: ["'none'"]
        }
    },
    hsts: {
        maxAge: 31536000,
        includeSubDomains: true,
        preload: true
    }
}));

// Rate limiting for session-related endpoints
const sessionLimiter = rateLimit({
    windowMs: 15 * 60 * 1000, // 15 minutes
    max: 10, // 10 requests per window
    message: { error: 'Too many session requests' },
    standardHeaders: true
});

class SecureCookieManager {
    constructor() {
        this.cookieConfig = this.createSecureCookieConfig();
        this.sessionConfig = this.createSecureSessionConfig();
    }
    
    createSecureCookieConfig() {
        const isProduction = process.env.NODE_ENV === 'production';
        
        return {
            // SECURE: Non-predictable cookie name
            name: process.env.SESSION_COOKIE_NAME || 'app_session_' + this.generateRandomSuffix(),
            
            // SECURE: Comprehensive cookie security settings
            cookie: {
                secure: isProduction, // HTTPS only in production
                httpOnly: true,       // Prevent JavaScript access
                maxAge: 30 * 60 * 1000, // 30 minutes
                sameSite: 'strict',   // Prevent CSRF
                path: '/',           // Limit cookie scope
                domain: isProduction ? process.env.COOKIE_DOMAIN : undefined
            },
            
            // SECURE: Additional security options
            proxy: isProduction, // Trust proxy in production
            rolling: true,       // Reset expiration on activity
            saveUninitialized: false, // Don't save empty sessions
            resave: false,       // Don't save unchanged sessions
            
            // SECURE: Strong session secret
            secret: this.getSessionSecret(),
            
            // SECURE: Custom session ID generator
            genid: this.generateSecureSessionId.bind(this)
        };
    }
    
    createSecureSessionConfig() {
        return {
            // Session timeout in milliseconds
            timeout: 30 * 60 * 1000, // 30 minutes
            
            // Maximum concurrent sessions per user
            maxConcurrentSessions: 5,
            
            // Session validation options
            validateIp: process.env.VALIDATE_SESSION_IP === 'true',
            validateUserAgent: process.env.VALIDATE_USER_AGENT === 'true',
            
            // Security monitoring
            enableSecurityLogging: true
        };
    }
    
    generateRandomSuffix() {
        return Math.random().toString(36).substring(2, 8);
    }
    
    getSessionSecret() {
        const secret = process.env.SESSION_SECRET;
        
        if (!secret) {
            throw new Error('SESSION_SECRET environment variable is required');
        }
        
        if (secret.length < 32) {
            throw new Error('SESSION_SECRET must be at least 32 characters long');
        }
        
        return secret;
    }
    
    generateSecureSessionId() {
        // SECURE: Cryptographically secure session ID
        const crypto = require('crypto');
        const timestamp = Date.now().toString(36);
        const randomBytes = crypto.randomBytes(32).toString('hex');
        
        // Combine timestamp and random data for uniqueness
        return `${timestamp}_${randomBytes}`;
    }
    
    // SECURE: Session middleware with comprehensive validation
    createSessionMiddleware() {
        return [
            // Apply rate limiting to session endpoints
            sessionLimiter,
            
            // Configure secure session
            session(this.cookieConfig),
            
            // Custom session validation middleware
            this.validateSessionSecurity.bind(this)
        ];
    }
    
    validateSessionSecurity(req, res, next) {
        // Skip validation for non-authenticated sessions
        if (!req.session || !req.session.isAuthenticated) {
            return next();
        }
        
        const currentTime = Date.now();
        const sessionTimeout = this.sessionConfig.timeout;
        
        // Check session timeout
        if (req.session.lastActivity) {
            const timeSinceLastActivity = currentTime - new Date(req.session.lastActivity).getTime();
            
            if (timeSinceLastActivity > sessionTimeout) {
                this.logSecurityEvent('session_timeout', {
                    sessionId: req.sessionID,
                    userId: req.session.userId,
                    timeSinceLastActivity: timeSinceLastActivity
                });
                
                return this.destroySessionAndRespond(req, res, 'Session expired');
            }
        }
        
        // Validate IP address if enabled
        if (this.sessionConfig.validateIp && req.session.originalIp) {
            const currentIp = this.getClientIp(req);
            
            if (req.session.originalIp !== currentIp) {
                this.logSecurityEvent('session_ip_change', {
                    sessionId: req.sessionID,
                    userId: req.session.userId,
                    originalIp: req.session.originalIp,
                    currentIp: currentIp
                });
                
                return this.destroySessionAndRespond(req, res, 'Session security violation');
            }
        }
        
        // Validate User Agent if enabled
        if (this.sessionConfig.validateUserAgent && req.session.originalUserAgent) {
            const currentUserAgent = req.get('User-Agent');
            
            if (req.session.originalUserAgent !== currentUserAgent) {
                this.logSecurityEvent('session_useragent_change', {
                    sessionId: req.sessionID,
                    userId: req.session.userId,
                    originalUserAgent: req.session.originalUserAgent,
                    currentUserAgent: currentUserAgent
                });
                
                // For User-Agent changes, log but don't destroy session
                // as this could be legitimate (browser updates, etc.)
            }
        }
        
        // Update last activity
        req.session.lastActivity = new Date().toISOString();
        
        next();
    }
    
    destroySessionAndRespond(req, res, message) {
        req.session.destroy((err) => {
            if (err) {
                console.error('Failed to destroy session:', err);
            }
            
            res.clearCookie(this.cookieConfig.name, this.cookieConfig.cookie);
            
            res.status(401).json({
                error: message,
                code: 'SESSION_INVALID',
                action: 'redirect_to_login'
            });
        });
    }
    
    // SECURE: Enhanced session creation with security attributes
    createSecureSession(req, user) {
        return new Promise((resolve, reject) => {
            // Regenerate session ID
            req.session.regenerate((err) => {
                if (err) {
                    return reject(err);
                }
                
                // Store user data securely
                req.session.isAuthenticated = true;
                req.session.userId = user.id;
                req.session.username = user.username;
                req.session.role = user.role;
                
                // Security tracking attributes
                req.session.createdAt = new Date().toISOString();
                req.session.lastActivity = new Date().toISOString();
                req.session.originalIp = this.getClientIp(req);
                req.session.originalUserAgent = req.get('User-Agent');
                req.session.loginMethod = 'password'; // Could be 'oauth', 'mfa', etc.
                
                // Security metadata
                req.session.securityLevel = this.calculateSecurityLevel(user, req);
                req.session.requiresMfa = user.requiresMfa || false;
                
                req.session.save((err) => {
                    if (err) {
                        return reject(err);
                    }
                    
                    this.logSecurityEvent('session_created', {
                        sessionId: req.sessionID,
                        userId: user.id,
                        username: user.username,
                        ipAddress: req.session.originalIp,
                        userAgent: req.session.originalUserAgent,
                        securityLevel: req.session.securityLevel
                    });
                    
                    resolve(req.sessionID);
                });
            });
        });
    }
    
    calculateSecurityLevel(user, req) {
        let level = 'normal';
        
        // High security for admin users
        if (user.role === 'admin' || user.role === 'superadmin') {
            level = 'high';
        }
        
        // High security for sensitive IP ranges
        const clientIp = this.getClientIp(req);
        if (this.isSensitiveIpRange(clientIp)) {
            level = 'high';
        }
        
        return level;
    }
    
    isSensitiveIpRange(ip) {
        // Define sensitive IP ranges (e.g., admin networks)
        const sensitiveRanges = process.env.SENSITIVE_IP_RANGES?.split(',') || [];
        return sensitiveRanges.some(range => ip.startsWith(range));
    }
    
    getClientIp(req) {
        return req.ip || 
               req.headers['x-forwarded-for']?.split(',')[0]?.trim() || 
               req.headers['x-real-ip'] || 
               req.connection.remoteAddress || 
               'unknown';
    }
    
    logSecurityEvent(event, data) {
        if (!this.sessionConfig.enableSecurityLogging) {
            return;
        }
        
        const logEntry = {
            timestamp: new Date().toISOString(),
            event: event,
            data: data,
            severity: this.getEventSeverity(event)
        };
        
        console.log('SESSION_SECURITY:', JSON.stringify(logEntry));
        
        // In production, send to security monitoring system
        // if (logEntry.severity === 'high') {
        //     securityAlerts.send(logEntry);
        // }
    }
    
    getEventSeverity(event) {
        const highSeverityEvents = [
            'session_ip_change',
            'session_fixation_attempt',
            'session_hijack_detected'
        ];
        
        return highSeverityEvents.includes(event) ? 'high' : 'medium';
    }
}

// Initialize secure cookie manager
const cookieManager = new SecureCookieManager();

// Apply secure session middleware
app.use(cookieManager.createSessionMiddleware());

// SECURE: Login endpoint with proper session creation
app.post('/login', async (req, res) => {
    try {
        const { username, password } = req.body;
        
        // Authenticate user (implement secure authentication)
        const user = await authenticateUser(username, password);
        
        if (!user) {
            return res.status(401).json({ error: 'Invalid credentials' });
        }
        
        // Create secure session
        await cookieManager.createSecureSession(req, user);
        
        res.json({
            success: true,
            user: {
                id: user.id,
                username: user.username,
                role: user.role
            },
            sessionExpiry: new Date(Date.now() + cookieManager.sessionConfig.timeout).toISOString()
        });
        
    } catch (error) {
        console.error('Login error:', error);
        res.status(500).json({ error: 'Internal server error' });
    }
});
3

Implement Cryptographically Secure Session ID Generation

Use cryptographically secure random number generators for session ID creation with sufficient entropy. Implement session ID validation, avoid predictable patterns, and ensure session IDs are unique and non-sequential.

View implementation – JAVASCRIPT
// SECURE: Cryptographically secure session ID generation
const crypto = require('crypto');
const { promisify } = require('util');

class SecureSessionIdGenerator {
    constructor() {
        this.sessionIdLength = 64; // 512 bits of entropy
        this.sessionIdRegex = /^[a-f0-9]{64}$/; // Hex validation pattern
        this.usedSessionIds = new Set(); // Track used IDs (use Redis in production)
        this.maxRetries = 10;
    }
    
    // SECURE: Generate cryptographically secure session ID
    async generateSessionId() {
        let attempts = 0;
        
        while (attempts < this.maxRetries) {
            try {
                // Use crypto.randomBytes for cryptographic security
                const randomBytes = crypto.randomBytes(this.sessionIdLength / 2);
                const sessionId = randomBytes.toString('hex');
                
                // Ensure uniqueness (important for high-traffic applications)
                if (!this.usedSessionIds.has(sessionId)) {
                    this.usedSessionIds.add(sessionId);
                    
                    // Clean up old session IDs periodically
                    if (this.usedSessionIds.size > 10000) {
                        this.cleanupOldSessionIds();
                    }
                    
                    return sessionId;
                }
                
                attempts++;
            } catch (error) {
                console.error('Error generating session ID:', error);
                attempts++;
            }
        }
        
        throw new Error('Failed to generate unique session ID after maximum retries');
    }
    
    // SECURE: Alternative method with additional entropy sources
    async generateEnhancedSessionId() {
        const timestamp = Date.now().toString(36);
        const randomPart1 = crypto.randomBytes(24).toString('hex');
        const randomPart2 = crypto.randomBytes(16).toString('base64url');
        const processId = process.pid.toString(36);
        
        // Combine multiple entropy sources
        const combinedEntropy = `${timestamp}${randomPart1}${randomPart2}${processId}`;
        
        // Hash the combined entropy for consistent length and format
        const hash = crypto.createHash('sha256').update(combinedEntropy).digest('hex');
        
        return hash;
    }
    
    // SECURE: Session ID validation
    validateSessionId(sessionId) {
        if (!sessionId || typeof sessionId !== 'string') {
            return {
                isValid: false,
                reason: 'Session ID must be a non-empty string'
            };
        }
        
        // Check length
        if (sessionId.length !== this.sessionIdLength) {
            return {
                isValid: false,
                reason: `Session ID must be exactly ${this.sessionIdLength} characters`
            };
        }
        
        // Check format (hexadecimal)
        if (!this.sessionIdRegex.test(sessionId)) {
            return {
                isValid: false,
                reason: 'Session ID contains invalid characters'
            };
        }
        
        // Check for predictable patterns
        if (this.hasPrerdictablePattern(sessionId)) {
            return {
                isValid: false,
                reason: 'Session ID contains predictable patterns'
            };
        }
        
        return {
            isValid: true,
            reason: 'Valid session ID'
        };
    }
    
    // SECURE: Detect predictable patterns in session IDs
    hasPredictablePattern(sessionId) {
        // Check for repeated characters
        const repeatedPattern = /(..).*\1.*\1/; // Same 2-char sequence repeated 3+ times
        if (repeatedPattern.test(sessionId)) {
            return true;
        }
        
        // Check for sequential patterns
        for (let i = 0; i < sessionId.length - 3; i++) {
            const char1 = parseInt(sessionId[i], 16);
            const char2 = parseInt(sessionId[i + 1], 16);
            const char3 = parseInt(sessionId[i + 2], 16);
            const char4 = parseInt(sessionId[i + 3], 16);
            
            // Check for ascending sequence
            if (char2 === char1 + 1 && char3 === char2 + 1 && char4 === char3 + 1) {
                return true;
            }
            
            // Check for descending sequence
            if (char2 === char1 - 1 && char3 === char2 - 1 && char4 === char3 - 1) {
                return true;
            }
        }
        
        // Check for common weak patterns
        const weakPatterns = [
            /^0+$/, // All zeros
            /^f+$/i, // All Fs
            /^(.)\1+$/, // All same character
            /(abcd|1234|0123)/i // Sequential patterns
        ];
        
        return weakPatterns.some(pattern => pattern.test(sessionId));
    }
    
    // SECURE: Clean up old session IDs from memory
    cleanupOldSessionIds() {
        // In production, implement proper cleanup based on session expiration
        // For now, clear half of the tracked IDs
        const idsArray = Array.from(this.usedSessionIds);
        const toKeep = idsArray.slice(idsArray.length / 2);
        
        this.usedSessionIds.clear();
        toKeep.forEach(id => this.usedSessionIds.add(id));
    }
    
    // SECURE: Generate session ID with custom entropy sources
    async generateSessionIdWithEntropy(additionalEntropy = {}) {
        const baseEntropy = crypto.randomBytes(32);
        
        // Collect additional entropy sources
        const entropyData = {
            timestamp: Date.now(),
            highResTime: process.hrtime.bigint().toString(),
            processId: process.pid,
            randomFloat: Math.random(),
            ...additionalEntropy
        };
        
        // Serialize entropy data
        const entropyString = JSON.stringify(entropyData);
        const entropyBuffer = Buffer.from(entropyString, 'utf8');
        
        // Combine base entropy with additional entropy
        const combinedEntropy = Buffer.concat([baseEntropy, entropyBuffer]);
        
        // Generate final session ID using PBKDF2 for additional security
        const salt = crypto.randomBytes(16);
        const sessionIdBuffer = crypto.pbkdf2Sync(combinedEntropy, salt, 10000, 32, 'sha256');
        
        return sessionIdBuffer.toString('hex');
    }
}

// SECURE: Session manager using secure ID generation
class SecureSessionManager {
    constructor() {
        this.idGenerator = new SecureSessionIdGenerator();
        this.sessions = new Map(); // Use Redis in production
        this.sessionTimeout = 30 * 60 * 1000; // 30 minutes
    }
    
    async createSession(userData, metadata = {}) {
        try {
            // Generate secure session ID
            const sessionId = await this.idGenerator.generateSessionId();
            
            // Validate the generated session ID
            const validation = this.idGenerator.validateSessionId(sessionId);
            if (!validation.isValid) {
                throw new Error(`Invalid session ID generated: ${validation.reason}`);
            }
            
            const sessionData = {
                id: sessionId,
                userId: userData.userId,
                username: userData.username,
                role: userData.role,
                createdAt: new Date(),
                lastAccessedAt: new Date(),
                expiresAt: new Date(Date.now() + this.sessionTimeout),
                ipAddress: metadata.ipAddress,
                userAgent: metadata.userAgent,
                isActive: true,
                securityLevel: metadata.securityLevel || 'normal'
            };
            
            // Store session
            this.sessions.set(sessionId, sessionData);
            
            // Log session creation
            this.logSessionEvent('session_created', {
                sessionId: sessionId,
                userId: userData.userId,
                metadata: metadata
            });
            
            return {
                sessionId: sessionId,
                expiresAt: sessionData.expiresAt
            };
            
        } catch (error) {
            console.error('Failed to create session:', error);
            throw new Error('Session creation failed');
        }
    }
    
    validateSession(sessionId, metadata = {}) {
        // Validate session ID format
        const validation = this.idGenerator.validateSessionId(sessionId);
        if (!validation.isValid) {
            this.logSessionEvent('invalid_session_id_format', {
                sessionId: sessionId,
                reason: validation.reason,
                metadata: metadata
            });
            return null;
        }
        
        // Get session data
        const session = this.sessions.get(sessionId);
        if (!session) {
            this.logSessionEvent('session_not_found', {
                sessionId: sessionId,
                metadata: metadata
            });
            return null;
        }
        
        // Check if session is active
        if (!session.isActive) {
            this.logSessionEvent('inactive_session_access', {
                sessionId: sessionId,
                userId: session.userId,
                metadata: metadata
            });
            return null;
        }
        
        // Check expiration
        if (new Date() > session.expiresAt) {
            this.destroySession(sessionId);
            this.logSessionEvent('expired_session_access', {
                sessionId: sessionId,
                userId: session.userId,
                expiredAt: session.expiresAt,
                metadata: metadata
            });
            return null;
        }
        
        // Update last access time
        session.lastAccessedAt = new Date();
        session.expiresAt = new Date(Date.now() + this.sessionTimeout);
        
        return session;
    }
    
    destroySession(sessionId) {
        const session = this.sessions.get(sessionId);
        
        if (session) {
            session.isActive = false;
            this.sessions.delete(sessionId);
            
            this.logSessionEvent('session_destroyed', {
                sessionId: sessionId,
                userId: session.userId
            });
        }
    }
    
    logSessionEvent(event, data) {
        const logEntry = {
            timestamp: new Date().toISOString(),
            event: event,
            data: data
        };
        
        console.log('SESSION_EVENT:', JSON.stringify(logEntry));
    }
}

// Usage example
const sessionManager = new SecureSessionManager();

module.exports = {
    SecureSessionIdGenerator,
    SecureSessionManager,
    sessionManager
};
4

Implement Comprehensive Session Lifecycle Management

Establish complete session lifecycle management including proper expiration, invalidation on logout, concurrent session limits, and security monitoring. Implement session cleanup mechanisms and audit trails for security compliance.

View implementation – JAVASCRIPT
// SECURE: Comprehensive session lifecycle management
const redis = require('redis');
const crypto = require('crypto');
const EventEmitter = require('events');

class SessionLifecycleManager extends EventEmitter {
    constructor(redisClient, options = {}) {
        super();
        this.redis = redisClient;
        this.options = {
            sessionTimeout: options.sessionTimeout || 30 * 60 * 1000, // 30 minutes
            maxConcurrentSessions: options.maxConcurrentSessions || 5,
            cleanupInterval: options.cleanupInterval || 5 * 60 * 1000, // 5 minutes
            enableAuditLogging: options.enableAuditLogging !== false,
            sessionExtendThreshold: options.sessionExtendThreshold || 5 * 60 * 1000, // 5 minutes
            ...options
        };
        
        this.startCleanupTimer();
        this.setupEventHandlers();
    }
    
    // SECURE: Complete session creation with lifecycle tracking
    async createSession(userData, requestMetadata = {}) {
        try {
            const sessionId = this.generateSecureSessionId();
            const now = new Date();
            const expiresAt = new Date(now.getTime() + this.options.sessionTimeout);
            
            const sessionData = {
                id: sessionId,
                userId: userData.userId,
                username: userData.username,
                role: userData.role,
                
                // Lifecycle timestamps
                createdAt: now.toISOString(),
                lastAccessedAt: now.toISOString(),
                expiresAt: expiresAt.toISOString(),
                lastExtendedAt: now.toISOString(),
                
                // Security metadata
                ipAddress: requestMetadata.ipAddress,
                userAgent: requestMetadata.userAgent,
                loginMethod: requestMetadata.loginMethod || 'password',
                
                // Session state
                isActive: true,
                securityLevel: this.calculateSecurityLevel(userData, requestMetadata),
                
                // Tracking
                accessCount: 1,
                lastRequestPath: requestMetadata.requestPath || '/',
                
                // Extension tracking
                extensionCount: 0,
                maxExtensions: 3 // Limit session extensions
            };
            
            // Enforce concurrent session limits
            await this.enforceConcurrentSessionLimits(userData.userId, sessionId);
            
            // Store session with automatic expiration
            const sessionKey = `session:${sessionId}`;
            const userSessionsKey = `user_sessions:${userData.userId}`;
            
            const pipeline = this.redis.pipeline();
            
            // Store session data
            pipeline.hset(sessionKey, sessionData);
            pipeline.expire(sessionKey, Math.ceil(this.options.sessionTimeout / 1000));
            
            // Track user's active sessions
            pipeline.sadd(userSessionsKey, sessionId);
            pipeline.expire(userSessionsKey, Math.ceil(this.options.sessionTimeout / 1000));
            
            // Store session metadata for quick lookups
            const metadataKey = `session_meta:${sessionId}`;
            pipeline.hset(metadataKey, {
                userId: userData.userId,
                createdAt: sessionData.createdAt,
                expiresAt: sessionData.expiresAt
            });
            pipeline.expire(metadataKey, Math.ceil(this.options.sessionTimeout / 1000));
            
            await pipeline.exec();
            
            // Emit session created event
            this.emit('sessionCreated', {
                sessionId,
                userId: userData.userId,
                sessionData,
                requestMetadata
            });
            
            // Log session creation
            await this.auditLog('session_created', {
                sessionId,
                userId: userData.userId,
                username: userData.username,
                ipAddress: requestMetadata.ipAddress,
                userAgent: requestMetadata.userAgent,
                securityLevel: sessionData.securityLevel
            });
            
            return {
                sessionId,
                expiresAt: sessionData.expiresAt,
                securityLevel: sessionData.securityLevel
            };
            
        } catch (error) {
            await this.auditLog('session_creation_failed', {
                userId: userData.userId,
                error: error.message,
                requestMetadata
            });
            throw error;
        }
    }
    
    // SECURE: Comprehensive session validation and extension
    async validateAndExtendSession(sessionId, requestMetadata = {}) {
        try {
            const sessionKey = `session:${sessionId}`;
            const sessionData = await this.redis.hgetall(sessionKey);
            
            if (!sessionData.id) {
                await this.auditLog('session_not_found', {
                    sessionId,
                    requestMetadata
                });
                return null;
            }
            
            // Check if session is active
            if (sessionData.isActive !== 'true') {
                await this.auditLog('inactive_session_access', {
                    sessionId,
                    userId: sessionData.userId,
                    requestMetadata
                });
                return null;
            }
            
            // Check expiration
            const now = new Date();
            const expiresAt = new Date(sessionData.expiresAt);
            
            if (now > expiresAt) {
                await this.destroySession(sessionId, 'expired');
                await this.auditLog('expired_session_access', {
                    sessionId,
                    userId: sessionData.userId,
                    expiredAt: sessionData.expiresAt,
                    requestMetadata
                });
                return null;
            }
            
            // Security validations
            const securityChecks = await this.performSecurityValidation(
                sessionData, 
                requestMetadata
            );
            
            if (!securityChecks.isValid) {
                await this.destroySession(sessionId, securityChecks.reason);
                await this.auditLog('session_security_violation', {
                    sessionId,
                    userId: sessionData.userId,
                    reason: securityChecks.reason,
                    requestMetadata
                });
                return null;
            }
            
            // Check if session should be extended
            const timeUntilExpiry = expiresAt.getTime() - now.getTime();
            const shouldExtend = timeUntilExpiry < this.options.sessionExtendThreshold;
            
            if (shouldExtend && this.canExtendSession(sessionData)) {
                await this.extendSession(sessionId, sessionData);
            }
            
            // Update session activity
            await this.updateSessionActivity(sessionId, requestMetadata);
            
            return {
                sessionId: sessionData.id,
                userId: sessionData.userId,
                username: sessionData.username,
                role: sessionData.role,
                securityLevel: sessionData.securityLevel,
                expiresAt: sessionData.expiresAt,
                lastAccessedAt: sessionData.lastAccessedAt
            };
            
        } catch (error) {
            console.error('Session validation error:', error);
            return null;
        }
    }
    
    // SECURE: Complete session destruction with cleanup
    async destroySession(sessionId, reason = 'manual') {
        try {
            const sessionKey = `session:${sessionId}`;
            const metadataKey = `session_meta:${sessionId}`;
            
            // Get session data before deletion
            const sessionData = await this.redis.hgetall(sessionKey);
            
            if (sessionData.userId) {
                const userSessionsKey = `user_sessions:${sessionData.userId}`;
                
                // Remove from user's session list
                await this.redis.srem(userSessionsKey, sessionId);
                
                // Emit session destroyed event
                this.emit('sessionDestroyed', {
                    sessionId,
                    userId: sessionData.userId,
                    reason,
                    sessionData
                });
                
                // Log session destruction
                await this.auditLog('session_destroyed', {
                    sessionId,
                    userId: sessionData.userId,
                    username: sessionData.username,
                    reason,
                    duration: sessionData.createdAt ? 
                        Date.now() - new Date(sessionData.createdAt).getTime() : null
                });
            }
            
            // Delete session data
            const pipeline = this.redis.pipeline();
            pipeline.del(sessionKey);
            pipeline.del(metadataKey);
            await pipeline.exec();
            
            return true;
            
        } catch (error) {
            console.error('Error destroying session:', error);
            return false;
        }
    }
    
    // SECURE: Destroy all sessions for a user
    async destroyAllUserSessions(userId, exceptSessionId = null, reason = 'logout_all') {
        try {
            const userSessionsKey = `user_sessions:${userId}`;
            const sessionIds = await this.redis.smembers(userSessionsKey);
            
            const sessionsToDestroy = exceptSessionId 
                ? sessionIds.filter(id => id !== exceptSessionId)
                : sessionIds;
            
            const destroyPromises = sessionsToDestroy.map(sessionId => 
                this.destroySession(sessionId, reason)
            );
            
            await Promise.all(destroyPromises);
            
            await this.auditLog('all_user_sessions_destroyed', {
                userId,
                sessionCount: sessionsToDestroy.length,
                exceptSessionId,
                reason
            });
            
            return sessionsToDestroy.length;
            
        } catch (error) {
            console.error('Error destroying all user sessions:', error);
            throw error;
        }
    }
    
    // SECURE: Enforce concurrent session limits
    async enforceConcurrentSessionLimits(userId, newSessionId) {
        const userSessionsKey = `user_sessions:${userId}`;
        const existingSessions = await this.redis.smembers(userSessionsKey);
        
        if (existingSessions.length >= this.options.maxConcurrentSessions) {
            // Get session creation times to remove oldest
            const sessionDetails = await Promise.all(
                existingSessions.map(async sessionId => {
                    const metaKey = `session_meta:${sessionId}`;
                    const meta = await this.redis.hgetall(metaKey);
                    return {
                        sessionId,
                        createdAt: new Date(meta.createdAt || 0)
                    };
                })
            );
            
            // Sort by creation time (oldest first)
            sessionDetails.sort((a, b) => a.createdAt - b.createdAt);
            
            // Remove excess sessions
            const sessionsToRemove = sessionDetails.slice(
                0, 
                sessionDetails.length - this.options.maxConcurrentSessions + 1
            );
            
            for (const session of sessionsToRemove) {
                await this.destroySession(session.sessionId, 'concurrent_limit_exceeded');
            }
            
            await this.auditLog('concurrent_session_limit_enforced', {
                userId,
                removedSessions: sessionsToRemove.length,
                maxAllowed: this.options.maxConcurrentSessions
            });
        }
    }
    
    // SECURE: Security validation for session access
    async performSecurityValidation(sessionData, requestMetadata) {
        const validations = [];
        
        // IP address validation
        if (sessionData.ipAddress && requestMetadata.ipAddress) {
            if (sessionData.ipAddress !== requestMetadata.ipAddress) {
                // For high security sessions, IP changes are not allowed
                if (sessionData.securityLevel === 'high') {
                    return {
                        isValid: false,
                        reason: 'ip_address_mismatch'
                    };
                }
                validations.push('ip_changed');
            }
        }
        
        // User agent validation (less strict)
        if (sessionData.userAgent && requestMetadata.userAgent) {
            if (sessionData.userAgent !== requestMetadata.userAgent) {
                validations.push('user_agent_changed');
            }
        }
        
        // Activity pattern analysis
        const accessCount = parseInt(sessionData.accessCount) || 0;
        const sessionAge = Date.now() - new Date(sessionData.createdAt).getTime();
        
        // Check for suspicious activity patterns
        if (accessCount > 1000 && sessionAge < 60000) { // 1000 requests in 1 minute
            return {
                isValid: false,
                reason: 'suspicious_activity_pattern'
            };
        }
        
        return {
            isValid: true,
            warnings: validations
        };
    }
    
    // SECURE: Update session activity tracking
    async updateSessionActivity(sessionId, requestMetadata) {
        const sessionKey = `session:${sessionId}`;
        const now = new Date().toISOString();
        
        const updates = {
            lastAccessedAt: now,
            accessCount: await this.redis.hincrby(sessionKey, 'accessCount', 1)
        };
        
        if (requestMetadata.requestPath) {
            updates.lastRequestPath = requestMetadata.requestPath;
        }
        
        await this.redis.hset(sessionKey, updates);
    }
    
    // SECURE: Session extension logic
    async extendSession(sessionId, sessionData) {
        const extensionCount = parseInt(sessionData.extensionCount) || 0;
        
        if (extensionCount >= sessionData.maxExtensions) {
            // Force re-authentication after max extensions
            await this.destroySession(sessionId, 'max_extensions_exceeded');
            return false;
        }
        
        const newExpiresAt = new Date(Date.now() + this.options.sessionTimeout);
        const sessionKey = `session:${sessionId}`;
        
        await this.redis.hset(sessionKey, {
            expiresAt: newExpiresAt.toISOString(),
            lastExtendedAt: new Date().toISOString(),
            extensionCount: extensionCount + 1
        });
        
        await this.redis.expire(sessionKey, Math.ceil(this.options.sessionTimeout / 1000));
        
        await this.auditLog('session_extended', {
            sessionId,
            userId: sessionData.userId,
            extensionCount: extensionCount + 1,
            newExpiresAt: newExpiresAt.toISOString()
        });
        
        return true;
    }
    
    canExtendSession(sessionData) {
        const extensionCount = parseInt(sessionData.extensionCount) || 0;
        return extensionCount < (sessionData.maxExtensions || 3);
    }
    
    // SECURE: Automated cleanup of expired sessions
    async cleanupExpiredSessions() {
        try {
            const sessionKeys = await this.redis.keys('session:*');
            let cleanedCount = 0;
            
            for (const sessionKey of sessionKeys) {
                const sessionData = await this.redis.hgetall(sessionKey);
                
                if (sessionData.expiresAt) {
                    const expiresAt = new Date(sessionData.expiresAt);
                    
                    if (new Date() > expiresAt) {
                        const sessionId = sessionKey.replace('session:', '');
                        await this.destroySession(sessionId, 'cleanup_expired');
                        cleanedCount++;
                    }
                }
            }
            
            if (cleanedCount > 0) {
                await this.auditLog('session_cleanup_completed', {
                    cleanedSessions: cleanedCount,
                    timestamp: new Date().toISOString()
                });
            }
            
            return cleanedCount;
            
        } catch (error) {
            console.error('Session cleanup error:', error);
            return 0;
        }
    }
    
    startCleanupTimer() {
        setInterval(() => {
            this.cleanupExpiredSessions();
        }, this.options.cleanupInterval);
    }
    
    setupEventHandlers() {
        this.on('sessionCreated', (data) => {
            console.log(`Session created: ${data.sessionId} for user ${data.userId}`);
        });
        
        this.on('sessionDestroyed', (data) => {
            console.log(`Session destroyed: ${data.sessionId} (${data.reason})`);
        });
    }
    
    generateSecureSessionId() {
        return crypto.randomBytes(32).toString('hex');
    }
    
    calculateSecurityLevel(userData, requestMetadata) {
        // Implement security level calculation based on user role and context
        if (userData.role === 'admin' || userData.role === 'superadmin') {
            return 'high';
        }
        
        return 'normal';
    }
    
    async auditLog(event, data) {
        if (!this.options.enableAuditLogging) {
            return;
        }
        
        const logEntry = {
            timestamp: new Date().toISOString(),
            event,
            data,
            source: 'SessionLifecycleManager'
        };
        
        // Store audit log
        const logKey = `audit:session:${Date.now()}:${crypto.randomBytes(4).toString('hex')}`;
        await this.redis.hset(logKey, logEntry);
        await this.redis.expire(logKey, 90 * 24 * 60 * 60); // Keep for 90 days
        
        console.log('SESSION_AUDIT:', JSON.stringify(logEntry));
    }
    
    // Get session statistics
    async getSessionStatistics() {
        const sessionKeys = await this.redis.keys('session:*');
        const userSessionKeys = await this.redis.keys('user_sessions:*');
        
        return {
            totalActiveSessions: sessionKeys.length,
            uniqueActiveUsers: userSessionKeys.length,
            timestamp: new Date().toISOString()
        };
    }
}

module.exports = SessionLifecycleManager;

Detect This Vulnerability in Your Code

Sourcery automatically identifies session fixation attack vulnerabilities in web applications and many other security issues in your codebase.