Insecure object reference - Session management - TypeScript

Insecure object reference - Session management - TypeScript

Need

Secure session management

Context

  • Usage of TypeScript for statically typed JavaScript development
  • Usage of Express for building web applications and APIs

Description

Non compliant code

        import express from 'express';

const app = express();

app.get('/logout', (req, res) => {
  const userEmail = req.query.email;
  // Code to close the session for the user with the provided email
  // ...
  res.send('Logged out successfully');
});

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

The vulnerability in this code is an insecure object reference in the session management.

In the /logout route, the code retrieves the email of the user from the query parameters using req.query.email. However, there is no validation or verification performed on this email parameter. This means that any user can potentially close the session of another user by simply knowing their email address.

This vulnerability allows an attacker to impersonate other users and forcefully log them out of the application. This can lead to unauthorized access to sensitive information or disruption of user sessions.

To mitigate this vulnerability, it is recommended to validate and verify the email parameter before closing the session. This can be done by comparing the email parameter with the email associated with the currently authenticated user. If they do not match, the logout action should be denied.

Steps

  • Implement a session management system that assigns a unique session identifier to each user upon login.
  • Store the session identifier in a secure manner, such as in a database or encrypted cookie.
  • When a user logs out, verify that the session identifier matches the one associated with the user's session.
  • If the session identifier is valid, close the session for that user.
  • Ensure that the session identifier cannot be easily guessed or manipulated by an attacker.
  • Test the updated code to ensure that it properly closes the session for the correct user.

Compliant code

        import express from 'express';
import { v4 as uuid } from 'uuid';

interface UserSession {
  email: string;
  sessionId: string;
}

const app = express();
const activeSessions: UserSession[] = [];

app.get('/logout', (req, res) => {
  const userEmail = req.query.email;
  const sessionId = req.query.sessionId;

  const sessionIndex = activeSessions.findIndex(session => session.email === userEmail && session.sessionId === sessionId);

  if (sessionIndex !== -1) {
    activeSessions.splice(sessionIndex, 1);
    res.send('Logged out successfully');
  } else {
    res.status(401).send('Invalid session');
  }
});

app.post('/login', (req, res) => {
  const userEmail = req.body.email;
  const sessionId = uuid();

  activeSessions.push({ email: userEmail, sessionId });

  // Code to handle successful login
  // ...

  res.send('Logged in successfully');
});

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

The fixed code addresses the vulnerability by implementing proper session management. Here's an explanation of the changes made:

1. An interface called UserSession is defined to represent a user session. It has two properties: email to store the user's email and sessionId to store the unique identifier for the session.

2. An array called activeSessions is created to store the active user sessions. Each session is represented by an object of type UserSession.

3. In the /logout route handler, the user's email and session ID are extracted from the request query parameters.

4. The findIndex method is used to search for the session in the activeSessions array that matches both the email and session ID provided. If a matching session is found, its index is returned.

5. If a matching session is found (i.e., sessionIndex is not -1), the session is removed from the activeSessions array using the splice method. This effectively logs out the user by closing their session.

6. If no matching session is found, a 401 Unauthorized response is sent to indicate an invalid session.

7. In the /login route handler, the user's email is extracted from the request body, and a new session ID is generated using the uuid function from the uuid library.

8. The new session is then added to the activeSessions array.

9. Finally, the server listens on port 3000 to handle incoming requests.

By validating the user's email and session ID in the logout process, the fixed code ensures that only the user associated with a specific session can close that session. This prevents unauthorized users from closing active sessions of other users.

References