logo

Database

Concurrent sessions control bypass

Need

Enforcement of concurrent session control

Context

• Usage of Ruby 2.0+ for developing Ruby applications

• Usage of Rails framework for building web applications

Description

1. Non compliant code

# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_action :check_concurrent_session

  private

  def check_concurrent_session
      @current_user = User.find(session[:user_id])...

In the above code, the `ApplicationController` has a `before_action` callback named `check_concurrent_session`. This method checks if the `session[:user_id]` exists, and if it does, it assigns the `@current_user` with the user found by the `session[:user_id]`. If the `session[:user_id]` does not exist, it redirects the user to the login page. The vulnerability here is that the `check_concurrent_session` method only checks if a session exists, but it does not verify if there is already an active session for the same user. This allows a user to bypass the concurrent session control by simply visiting any valid URL in the application when the error that there is already a session started appears. This can lead to situations where a single user can have multiple active sessions at the same time, potentially leading to security issues such as session hijacking or privilege escalation.

2. Steps

• Implement a session management mechanism that keeps track of active sessions.

• When a user logs in, store the session ID in a secure manner (e.g., encrypted) and associate it with the user.

• When a user tries to access a URL, check if the session ID is valid and associated with the user.

• If the session ID is invalid or not associated with the user, redirect the user to the login page with an appropriate message.

• Ensure that the session ID is invalidated and removed from the session management mechanism when the user logs out or the session expires.

• Consider implementing additional security measures such as limiting the number of concurrent sessions per user or implementing session timeout.

3. Secure code example

# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_action :check_concurrent_session

  private

  def check_concurrent_session
      @current_user = User.find(session[:user_id])...

The updated code now includes a session management mechanism that keeps track of active sessions. In the `ApplicationController`, the `check_concurrent_session` method now checks if the session ID stored in the user's session matches the session ID associated with the user in the database. If the session IDs do not match, the session is reset and the user is redirected to the login page with an appropriate message. In the `User` model, a `generate_session_id` method is added which is called after a user is created. This method generates a secure random session ID and saves it to the user's record in the database. This way, even if a user tries to bypass the concurrent session control by going to any valid URL in the application when the error that there is already a session started appears, they will be redirected to the login page because the session IDs will not match. This solution also ensures that the session ID is invalidated and removed from the session management mechanism when the user logs out or the session expires. For additional security, consider implementing measures such as limiting the number of concurrent sessions per user or implementing session timeout.