Concurrent sessions control bypass - Java

Concurrent sessions control bypass - Java

Need

Enforcement of concurrent session control

Context

  • Usage of Java 8 for developing applications with enhanced features and performance improvements
  • Usage of javax.servlet-api for building Java web applications with Servlets

Description

Non compliant code

        import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletRequest;

public void handleRequest(HttpServletRequest request) {
    HttpSession session = request.getSession(false);
    if (session != null) {
        // Do something with the session
    } else {
        session = request.getSession(true);
    }
}
        
        

The above code is an example of a Servlet that handles HTTP requests in a Java-based web application. Here, the handleRequest method is trying to retrieve an existing HTTP session, if it exists, otherwise it creates a new one.

The vulnerability lies in the fact that this code does not properly handle concurrent sessions. When a user is already logged in and has an active session, and then they try to start a new session from a different browser or device, this code will simply create a new session for them. This allows the user to bypass the concurrent session control.

The problem arises when the application is not checking if there is already an active session for the user. If there is, the application should not create a new session, but instead return an error message to the user, notifying them that they are already logged in elsewhere.

This lack of control can lead to situations where a user can have multiple active sessions at the same time, which can cause issues with data consistency and can potentially be exploited by an attacker to gain unauthorized access to the system.

Steps

  • Implement a mechanism to track and limit the number of concurrent sessions per user.
  • When a user tries to start a new session, check if the maximum number of concurrent sessions has been reached.
  • If the maximum number of sessions has been reached, prevent the user from starting a new session and display an appropriate error message.
  • If the maximum number of sessions has not been reached, allow the user to start a new session.
  • Ensure that the session management mechanism is secure and cannot be bypassed.

Compliant code

        import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.ConcurrentHashMap;

public class SessionManager {
    private static final int MAX_SESSIONS_PER_USER = 1; // Set your limit
    private static ConcurrentHashMap activeSessions = new ConcurrentHashMap<>();

    public static void handleRequest(HttpServletRequest request) {
        HttpSession session = request.getSession(false);
        if (session != null && session.getAttribute("username") != null) {
            if (activeSessions.contains(session.getAttribute("username"))) {
                // Do something with the session
            } else {
                // Session exists but not in activeSessions map, so invalidate it
                session.invalidate();
                throw new RuntimeException("Maximum number of sessions reached");
            }
        } else {
            if (activeSessions.size() < MAX_SESSIONS_PER_USER) {
                session = request.getSession(true);
                activeSessions.put((String) session.getAttribute("username"), session);
            } else {
                throw new RuntimeException("Maximum number of sessions reached");
            }
        }
    }
}
        
        

The above code fixes the vulnerability by implementing a mechanism to track and limit the number of concurrent sessions per user.

A ConcurrentHashMap named activeSessions is used to store the active sessions. The key is the username and the value is the session.

When a user tries to start a new session, the handleRequest method checks if the maximum number of concurrent sessions ( MAX_SESSIONS_PER_USER) has been reached.

If the maximum number of sessions has been reached, the user is prevented from starting a new session and a RuntimeException with an appropriate error message is thrown.

If the maximum number of sessions has not been reached, the user is allowed to start a new session and the session is added to the activeSessions map.

If a session exists but is not in the activeSessions map, it is invalidated. This ensures that the session management mechanism is secure and cannot be bypassed.

References