Introduction
Getting Started
- QuickStart
Patterns
- Languages
- Security
- Injection Vulnerabilities
- Authentication Vulnerabilities
- Authorization Vulnerabilities
- Cryptography Vulnerabilities
- Data Protection Vulnerabilities
- Input Validation Vulnerabilities
- Session Management Vulnerabilities
- Error Handling Vulnerabilities
- Logging Vulnerabilities
- Configuration Vulnerabilities
- File Handling Vulnerabilities
- Memory Management Vulnerabilities
- API Security Vulnerabilities
- Cross-Site Scripting Vulnerabilities
- Cross-Site Request Forgery Vulnerabilities
- Insecure Deserialization Vulnerabilities
- Security Misconfiguration Vulnerabilities
- Broken Access Control Vulnerabilities
- Sensitive Data Exposure Vulnerabilities
- XML Vulnerabilities
- Regular Expression Denial of Service (ReDoS)
- Performance
Integrations
- Code Repositories
- Team Messengers
- Ticketing
Enterprise
Session management vulnerabilities occur when applications fail to properly create, maintain, or terminate user sessions, potentially allowing attackers to hijack sessions or impersonate users.
Session management is the process of securely handling user sessions throughout their lifecycle, from creation to termination. Proper session management is critical for maintaining user authentication state and protecting user accounts.
Session management vulnerabilities can lead to session hijacking, session fixation, cross-site request forgery, and other attacks that compromise user accounts and data. Implementing secure session management practices is essential for protecting user privacy and maintaining application security.
// Anti-pattern: Insecure session IDs
function generateSessionId() {
// Using predictable values for session IDs
return Date.now().toString();
}
// Better approach: Secure session ID generation
const crypto = require('crypto');
function generateSessionId() {
// Using cryptographically secure random values
return crypto.randomBytes(32).toString('hex');
}
Insecure session IDs that are predictable, short, or follow a pattern can be guessed or brute-forced by attackers, leading to session hijacking.
To implement secure session IDs:
- Use cryptographically secure random number generators
- Ensure sufficient entropy and length (at least 128 bits)
- Avoid using predictable values like timestamps or sequential numbers
- Regenerate session IDs after authentication
- Use session management libraries or frameworks that implement secure practices
// Anti-pattern: Missing session expiration
app.use(session({
secret: 'session-secret',
resave: false,
saveUninitialized: true,
cookie: {
// No expiration set
}
}));
// Better approach: Proper session expiration
app.use(session({
secret: 'session-secret',
resave: false,
saveUninitialized: true,
cookie: {
// Set both expiration and maxAge
expires: new Date(Date.now() + 3600000), // 1 hour
maxAge: 3600000, // 1 hour in milliseconds
secure: true,
httpOnly: true
}
}));
Missing session expiration can lead to prolonged session validity, increasing the risk of session hijacking and unauthorized access.
To implement proper session expiration:
- Set appropriate timeout periods for sessions (e.g., 15-30 minutes for sensitive applications)
- Implement both idle timeout and absolute timeout
- Provide session extension mechanisms for active users
- Automatically invalidate sessions after password changes
- Consider risk-based session timeouts based on user activity and context
// Anti-pattern: Insecure session storage
// Using memory store in production
app.use(session({
secret: 'session-secret',
resave: false,
saveUninitialized: true
// Default memory store (not suitable for production)
}));
// Better approach: Secure session storage
const RedisStore = require('connect-redis').default;
const redis = require('redis');
// Create Redis client
const redisClient = redis.createClient({
host: process.env.REDIS_HOST,
port: process.env.REDIS_PORT,
password: process.env.REDIS_PASSWORD,
tls: process.env.NODE_ENV === 'production' ? {} : undefined
});
app.use(session({
store: new RedisStore({ client: redisClient }),
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: {
secure: process.env.NODE_ENV === 'production',
httpOnly: true,
maxAge: 3600000 // 1 hour
}
}));
Insecure session storage can lead to session data leakage, session hijacking, or denial-of-service attacks.
To implement secure session storage:
- Use a production-ready session store (Redis, MongoDB, etc.)
- Encrypt session data at rest
- Implement proper authentication for the session store
- Ensure high availability and performance of the session store
- Regularly back up session data
- Implement proper session cleanup mechanisms
// Anti-pattern: Vulnerable to session fixation
app.post('/login', (req, res) => {
const { username, password } = req.body;
authenticateUser(username, password)
.then(user => {
if (user) {
// Using the same session ID after login
req.session.userId = user.id;
res.redirect('/dashboard');
} else {
res.render('login', { error: 'Invalid credentials' });
}
})
.catch(err => res.status(500).render('error', { error: err.message }));
});
// Better approach: Preventing session fixation
app.post('/login', (req, res) => {
const { username, password } = req.body;
authenticateUser(username, password)
.then(user => {
if (user) {
// Regenerate session ID after successful authentication
req.session.regenerate(err => {
if (err) {
return res.status(500).render('error', { error: 'Session error' });
}
// Set user data in the new session
req.session.userId = user.id;
res.redirect('/dashboard');
});
} else {
res.render('login', { error: 'Invalid credentials' });
}
})
.catch(err => res.status(500).render('error', { error: err.message }));
});
Session fixation occurs when an attacker sets a user’s session ID to one known to the attacker, allowing them to hijack the session after the user authenticates.
To prevent session fixation:
- Regenerate session IDs after authentication
- Invalidate existing sessions when users authenticate
- Implement proper session ID validation
- Use secure, HttpOnly, and SameSite cookies
- Implement additional session validation mechanisms
// Anti-pattern: Insecure session cookies
app.use(session({
secret: 'session-secret',
resave: false,
saveUninitialized: true,
cookie: {
// Missing security attributes
}
}));
// Better approach: Secure session cookies
app.use(session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: {
secure: process.env.NODE_ENV === 'production', // Requires HTTPS
httpOnly: true, // Prevents JavaScript access
sameSite: 'strict', // Prevents CSRF
maxAge: 3600000, // 1 hour
domain: process.env.COOKIE_DOMAIN, // Restrict to specific domain
path: '/' // Restrict to specific path
}
}));
Insecure session cookies can be stolen, manipulated, or used in cross-site request forgery attacks.
To implement secure session cookies:
- Use the HttpOnly flag to prevent JavaScript access
- Use the Secure flag to ensure cookies are only sent over HTTPS
- Implement the SameSite attribute to prevent CSRF
- Set appropriate domain and path restrictions
- Use appropriate expiration times
- Consider implementing cookie prefixes for additional security
// Anti-pattern: Missing CSRF protection
app.post('/api/update-profile', (req, res) => {
// No CSRF token validation
updateUserProfile(req.session.userId, req.body)
.then(() => res.json({ success: true }))
.catch(err => res.status(500).json({ error: err.message }));
});
// Better approach: Implementing CSRF protection
const csrf = require('csurf');
const csrfProtection = csrf({ cookie: true });
// Generate CSRF token
app.get('/profile', csrfProtection, (req, res) => {
res.render('profile', { csrfToken: req.csrfToken() });
});
// Validate CSRF token
app.post('/api/update-profile', csrfProtection, (req, res) => {
updateUserProfile(req.session.userId, req.body)
.then(() => res.json({ success: true }))
.catch(err => res.status(500).json({ error: err.message }));
});
Missing CSRF protection can allow attackers to trick users into performing unwanted actions on a website where they’re authenticated.
To implement CSRF protection:
- Use CSRF tokens for state-changing operations
- Implement proper token validation
- Use the SameSite cookie attribute
- Consider using CSRF protection middleware
- Implement proper error handling for CSRF validation failures
// Anti-pattern: Insufficient session validation
function isAuthenticated(req, res, next) {
// Only checking if userId exists in session
if (req.session.userId) {
return next();
}
res.redirect('/login');
}
// Better approach: Comprehensive session validation
function isAuthenticated(req, res, next) {
// Check if session exists
if (!req.session) {
return res.redirect('/login');
}
// Check if user is authenticated
if (!req.session.userId) {
return res.redirect('/login');
}
// Verify user still exists and is active
getUserById(req.session.userId)
.then(user => {
if (!user || user.isDisabled) {
// Destroy session if user doesn't exist or is disabled
return req.session.destroy(() => {
res.redirect('/login');
});
}
// Check if session is expired based on last activity
const lastActivity = req.session.lastActivity || 0;
const currentTime = Date.now();
const maxInactiveInterval = 30 * 60 * 1000; // 30 minutes
if (currentTime - lastActivity > maxInactiveInterval) {
return req.session.destroy(() => {
res.redirect('/login?expired=true');
});
}
// Update last activity time
req.session.lastActivity = currentTime;
// Add user to request object for convenience
req.user = user;
next();
})
.catch(err => {
console.error('Session validation error:', err);
res.redirect('/login');
});
}
Insufficient session validation can allow attackers to use expired, invalid, or stolen session identifiers to gain unauthorized access.
To implement comprehensive session validation:
- Verify session existence and validity
- Validate user existence and status
- Implement activity-based session timeout
- Check for additional session attributes (IP address, user agent)
- Consider implementing step-up authentication for sensitive operations
- Log and monitor suspicious session activity
// Anti-pattern: Improper session termination
app.get('/logout', (req, res) => {
// Only clearing session data, not destroying the session
req.session.userId = null;
res.redirect('/login');
});
// Better approach: Proper session termination
app.get('/logout', (req, res) => {
// Completely destroy the session
req.session.destroy(err => {
if (err) {
console.error('Session destruction error:', err);
}
// Clear session cookie
res.clearCookie('connect.sid', {
path: '/',
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'strict'
});
res.redirect('/login');
});
});
Improper session termination can leave active sessions that can be reused by attackers, even after users believe they have logged out.
To implement proper session termination:
- Completely destroy server-side session data
- Clear session cookies on the client
- Implement proper error handling for session destruction
- Consider invalidating all user sessions on password change
- Log session termination events
// Anti-pattern: Storing sensitive session data on the client
function login(username, password) {
return authenticateUser(username, password)
.then(user => {
if (user) {
// Storing sensitive data in localStorage
localStorage.setItem('user_id', user.id);
localStorage.setItem('user_role', user.role);
localStorage.setItem('auth_token', user.token);
return true;
}
return false;
});
}
// Better approach: Storing minimal data on the client
function login(username, password) {
return authenticateUser(username, password)
.then(user => {
if (user) {
// Store only the authentication token in a secure cookie
// Server will handle session management
document.cookie = `auth_token=${user.token}; path=/; secure; HttpOnly; SameSite=Strict`;
return true;
}
return false;
});
}
Storing sensitive session data on the client (localStorage, sessionStorage) exposes it to cross-site scripting attacks and other client-side vulnerabilities.
To implement secure client-side storage:
- Minimize data stored on the client
- Use secure cookies for authentication tokens
- Never store sensitive data in localStorage or sessionStorage
- Implement proper token validation on the server
- Consider using JWT with appropriate security measures
// Anti-pattern: No session monitoring
// Application with no session monitoring capabilities
// Better approach: Implementing session monitoring
function isAuthenticated(req, res, next) {
if (!req.session || !req.session.userId) {
return res.redirect('/login');
}
// Get client information
const clientIp = req.ip;
const userAgent = req.headers['user-agent'];
// Check if session has recorded client information
if (!req.session.clientIp || !req.session.userAgent) {
// First request with this session, record client information
req.session.clientIp = clientIp;
req.session.userAgent = userAgent;
} else if (req.session.clientIp !== clientIp || req.session.userAgent !== userAgent) {
// Client information changed, potential session hijacking
logger.warn('Potential session hijacking detected', {
userId: req.session.userId,
originalIp: req.session.clientIp,
newIp: clientIp,
originalUserAgent: req.session.userAgent,
newUserAgent: userAgent,
sessionId: req.sessionID
});
// Destroy the session and require re-authentication
return req.session.destroy(() => {
res.redirect('/login?security=true');
});
}
// Update last activity
req.session.lastActivity = Date.now();
// Log session activity
logger.info('Session activity', {
userId: req.session.userId,
path: req.path,
method: req.method,
ip: clientIp,
sessionId: req.sessionID
});
next();
}
Missing session monitoring can allow session hijacking or unauthorized access to go undetected.
To implement session monitoring:
- Log session creation, usage, and termination
- Monitor for suspicious session activity
- Implement anomaly detection for session usage
- Track client information (IP, user agent) for session validation
- Consider implementing session fingerprinting
- Set up alerts for potential session attacks
// Anti-pattern: No concurrent session management
// Application that allows unlimited concurrent sessions
// Better approach: Implementing concurrent session management
function login(req, res) {
const { username, password } = req.body;
authenticateUser(username, password)
.then(user => {
if (!user) {
return res.render('login', { error: 'Invalid credentials' });
}
// Check active sessions for this user
return getActiveSessions(user.id)
.then(sessions => {
const maxConcurrentSessions = 3;
if (sessions.length >= maxConcurrentSessions) {
// Option 1: Prevent new login
// return res.render('login', {
// error: 'Maximum number of concurrent sessions reached. Please log out from another device.'
// });
// Option 2: Terminate oldest session
const oldestSession = sessions.reduce((oldest, current) => {
return current.lastActivity < oldest.lastActivity ? current : oldest;
});
return terminateSession(oldestSession.id)
.then(() => {
// Create new session
req.session.regenerate(err => {
if (err) {
return res.status(500).render('error', { error: 'Session error' });
}
req.session.userId = user.id;
req.session.username = user.username;
req.session.lastActivity = Date.now();
// Record session information
recordSession({
userId: user.id,
sessionId: req.sessionID,
userAgent: req.headers['user-agent'],
ip: req.ip,
createdAt: new Date()
});
res.redirect('/dashboard');
});
});
}
// Create new session
req.session.regenerate(err => {
if (err) {
return res.status(500).render('error', { error: 'Session error' });
}
req.session.userId = user.id;
req.session.username = user.username;
req.session.lastActivity = Date.now();
// Record session information
recordSession({
userId: user.id,
sessionId: req.sessionID,
userAgent: req.headers['user-agent'],
ip: req.ip,
createdAt: new Date()
});
res.redirect('/dashboard');
});
});
})
.catch(err => res.status(500).render('error', { error: err.message }));
}
Lack of concurrent session management can allow attackers to establish multiple sessions, potentially leading to account sharing or unauthorized access.
To implement concurrent session management:
- Limit the number of active sessions per user
- Provide visibility into active sessions
- Allow users to terminate other sessions
- Implement session prioritization policies
- Log and monitor concurrent session usage
- Consider risk-based session limits
// Anti-pattern: Insecure session data storage
app.post('/checkout', (req, res) => {
// Storing sensitive data in the session
req.session.creditCard = req.body.creditCard;
req.session.cvv = req.body.cvv;
req.session.cardholderName = req.body.cardholderName;
res.redirect('/confirm-order');
});
// Better approach: Secure handling of sensitive data
app.post('/checkout', (req, res) => {
// Process payment immediately instead of storing sensitive data
processPayment({
creditCard: req.body.creditCard,
cvv: req.body.cvv,
cardholderName: req.body.cardholderName,
amount: req.session.cartTotal
})
.then(paymentResult => {
// Store only the payment reference, not the sensitive data
req.session.paymentReference = paymentResult.referenceId;
req.session.paymentStatus = paymentResult.status;
res.redirect('/confirm-order');
})
.catch(err => {
res.render('checkout', { error: 'Payment processing failed' });
});
});
Storing sensitive data in session storage can lead to data exposure if the session store is compromised or if there are vulnerabilities in the session management system.
To implement secure session data storage:
- Minimize sensitive data stored in sessions
- Process sensitive data immediately rather than storing it
- Encrypt sensitive session data when storage is necessary
- Implement proper access controls for the session store
- Regularly purge unnecessary session data
- Consider using specialized secure storage for sensitive data
// Anti-pattern: Missing secure flag on cookies
app.use(session({
secret: 'session-secret',
resave: false,
saveUninitialized: true,
cookie: {
httpOnly: true,
// Missing secure flag
}
}));
// Better approach: Implementing secure flag
app.use(session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: {
httpOnly: true,
secure: process.env.NODE_ENV === 'production', // Requires HTTPS
sameSite: 'strict'
}
}));
Missing the secure flag on cookies allows session cookies to be transmitted over unencrypted HTTP connections, potentially exposing them to interception.
To implement secure cookies:
- Always set the secure flag in production environments
- Implement HTTPS across your entire application
- Use the HttpOnly flag to prevent JavaScript access
- Implement the SameSite attribute to prevent CSRF
- Consider using cookie prefixes for additional security
- Implement proper cookie expiration
// Anti-pattern: Insufficient session entropy
function generateSessionId() {
// Using low-entropy method
return Math.random().toString(36).substring(2, 15);
}
// Better approach: High-entropy session IDs
const crypto = require('crypto');
function generateSessionId() {
// Using high-entropy cryptographic method
return crypto.randomBytes(32).toString('hex');
}
Insufficient entropy in session IDs makes them more predictable and vulnerable to brute force or guessing attacks.
To implement high-entropy session IDs:
- Use cryptographically secure random number generators
- Ensure sufficient length for session IDs (at least 128 bits)
- Avoid using predictable inputs for session ID generation
- Use session management libraries that implement secure ID generation
- Regularly rotate session IDs
- Monitor for brute force attempts against session IDs
// Anti-pattern: No session hijacking prevention
// Application with no protection against session hijacking
// Better approach: Implementing session hijacking prevention
app.use((req, res, next) => {
// Skip for non-authenticated routes
if (!req.session || !req.session.userId) {
return next();
}
// Get client information
const clientIp = req.ip;
const userAgent = req.headers['user-agent'];
// Check if session has recorded client information
if (!req.session.clientIp || !req.session.userAgent) {
// First request with this session, record client information
req.session.clientIp = clientIp;
req.session.userAgent = userAgent;
return next();
}
// Verify client information matches
const ipChanged = req.session.clientIp !== clientIp;
const userAgentChanged = req.session.userAgent !== userAgent;
if (ipChanged || userAgentChanged) {
// Potential session hijacking
logger.warn('Potential session hijacking detected', {
userId: req.session.userId,
sessionId: req.sessionID,
originalIp: req.session.clientIp,
newIp: clientIp,
ipChanged,
userAgentChanged
});
// Option 1: Terminate session
return req.session.destroy(() => {
res.redirect('/login?security=true');
});
// Option 2: Require re-authentication
// req.session.requireReauth = true;
// return res.redirect('/verify-identity');
}
next();
});
Without session hijacking prevention measures, attackers who obtain session identifiers can impersonate legitimate users.
To prevent session hijacking:
- Implement transport layer security (HTTPS)
- Use secure, HttpOnly, and SameSite cookies
- Bind sessions to client attributes (IP, user agent)
- Implement session fingerprinting
- Regularly regenerate session IDs
- Monitor for suspicious session activity
- Consider implementing multi-factor authentication