Skip to main content

Concurrent sessions

Need

Enforcement of session limits and notification of concurrent sessions

Context

  • Usage of TypeScript for static typing and enhanced development experience in Node.js
  • Usage of Express for building web applications and handling HTTP requests
  • Usage of express-session for managing user sessions in Express

Description

Non compliant code

import express from 'express';
import session from 'express-session';

const app = express();

app.use(session({
secret: 'mysecretkey',
resave: false,
saveUninitialized: true
}));

app.post('/login', (req, res) => {
const { username, password } = req.body;

// Authenticate user and create session
// ...

res.send('Login successful');
});

app.listen(3000, () => {
console.log('Server started on port 3000');
});

The vulnerability in this code is the lack of validation for the number of active sessions each user can have. The code does not restrict the user from logging in multiple times simultaneously.

This means that a user can log in from multiple devices or locations at the same time without any notification or restriction. This can lead to several issues:

  1. Traceability: With multiple active sessions, it becomes difficult to track and trace the actions performed by a specific user. This can hinder the ability to investigate any suspicious or malicious activities.

  2. Non-repudiation: When a user performs an action, it should be possible to prove that the user actually performed it. With concurrent sessions, it becomes challenging to establish the authenticity of the user's actions, as multiple sessions can be active simultaneously.

To address this vulnerability, the system should restrict the number of concurrent sessions a user can establish. Additionally, the user should be notified when a login from a different location occurs.

Steps

  • Install and import the 'connect-session-sequelize' package to manage sessions with a database.
  • Create a Sequelize instance and configure it to connect to your database.
  • Create a new model for the session using Sequelize, defining the necessary fields.
  • Associate the session model with the user model to establish a relationship.
  • Update the session configuration in the 'app.use' middleware to use the 'connect-session-sequelize' store.
  • Set the 'maxAge' option in the session configuration to define the session expiration time.
  • Set the 'limit' option in the session configuration to restrict the number of concurrent sessions per user.
  • Add logic in the '/login' route to check if the user already has an active session and notify them if a new session is initiated from a different location.
  • Implement the necessary logic to handle session expiration and removal of expired sessions from the database.
  • Test the application thoroughly to ensure the concurrent session restriction and notification functionality is working as expected.

Compliant code

import express from 'express';
import session from 'express-session';
import { Sequelize } from 'sequelize';
import SequelizeStore from 'connect-session-sequelize';

const app = express();

// Step 2: Create a Sequelize instance and configure it to connect to your database
const sequelize = new Sequelize('database', 'username', 'password', {
host: 'localhost',
dialect: 'mysql',
});

// Step 3: Create a new model for the session using Sequelize, defining the necessary fields
const Session = sequelize.define('Session', {
sid: {
type: Sequelize.STRING,
primaryKey: true,
},
userId: Sequelize.INTEGER,
expires: Sequelize.DATE,
data: Sequelize.TEXT,
});

// Step 4: Associate the session model with the user model to establish a relationship
// Replace 'User' with your actual user model
Session.belongsTo(User);

// Step 5: Update the session configuration to use the 'connect-session-sequelize' store
const sessionStore = new SequelizeStore({
db: sequelize,
table: 'Session',
});

app.use(
session({
secret: 'mysecretkey',
resave: false,
saveUninitialized: true,
store: sessionStore,
maxAge: 3600000, // Step 6: Set the session expiration time (1 hour)
limit: 1, // Step 7: Set the maximum number of concurrent sessions per user
})
);

app.post('/login', (req, res) => {
const { username, password } = req.body;

// Step 8: Add logic to check if the user already has an active session
if (req.session.userId) {
// Notify the user that a new session is initiated from a different location
res.send('You are already logged in from another location');
return;
}

// Authenticate user and create session
// ...

res.send('Login successful');
});

// Step 9: Implement logic to handle session expiration and removal of expired sessions from the database
sessionStore.sync();

app.listen(3000, () => {
console.log('Server started on port 3000');
});

The fixed code addresses the vulnerability of concurrent sessions by implementing several measures.

  1. The code imports the necessary modules, including Express, Express Session, Sequelize, and Connect Session Sequelize.

  2. It creates a Sequelize instance and configures it to connect to the database.

  3. A new model for the session is defined using Sequelize, specifying the required fields such as session ID, user ID, expiration time, and data.

  4. The session model is associated with the user model to establish a relationship.

  5. The session configuration is updated to use the Connect Session Sequelize store, which allows storing sessions in the database.

  6. The session middleware is added to the Express app, with options such as a secret key, session store, session expiration time (1 hour), and maximum number of concurrent sessions per user (limit: 1).

  7. In the login route, logic is added to check if the user already has an active session. If so, the user is notified that a new session is initiated from a different location.

  8. After authenticating the user and creating a session, a success message is sent back to the client.

  9. Logic is implemented to handle session expiration and removal of expired sessions from the database.

Overall, the fixed code restricts the number of concurrent sessions per user and notifies the user when a login from a different location occurs. It ensures that the session data is securely stored in the database and provides traceability and non-repudiation of user actions.

References