Skip to main content

Concurrent sessions

Need

Enforce session management and limit concurrent user sessions

Context

  • Usage of Ruby 2.0+ for developing Ruby applications
  • Usage of Ruby on Rails for web application development

Description

Non compliant code

class SessionsController < ApplicationController
def create
user = User.find_by(email: params[:email])
if user && user.authenticate(params[:password])
session[:user_id] = user.id
redirect_to root_url, notice: "Logged in!"
else
flash.now[:alert] = "Email or password is invalid"
render "new"
end
end
end

In the code snippet above, we have a SessionsController with a create method that handles user login. The user is found by their email, and if the user exists and the password is authenticated, a new session is created for that user.

The vulnerability here is that there is no check to see if a session already exists for the user. This means that the user could potentially be logged in from multiple locations, creating multiple sessions. This can lead to security risks, such as session hijacking or fixation.

Furthermore, the application does not notify the user when a session has already been initiated or when a second one commences from a different location. This lack of notification means that the user may be unaware that their account is being accessed from another location, which could potentially be a malicious actor.

The lack of session validation and notification is a significant security issue that needs to be addressed.

Steps

  • Implement session management to track active sessions for each user
  • When a user logs in, check if they already have an active session
  • If the user has an active session, notify them and give them the option to terminate the previous session
  • Prevent multiple concurrent sessions for the same user
  • Implement session expiration to automatically log out inactive sessions
  • Consider implementing multi-factor authentication to enhance security

Compliant code

class SessionsController < ApplicationController
def create
user = User.find_by(email: params[:email])
if user && user.authenticate(params[:password])
if session[:user_id]
flash[:alert] = "You are already logged in from another location. Do you want to terminate the previous session?"
redirect_to terminate_previous_session_path
else
session[:user_id] = user.id
session[:expires_at] = Time.current + 1.hour
redirect_to root_url, notice: "Logged in!"
end
else
flash.now[:alert] = "Email or password is invalid"
render "new"
end
end

def terminate_previous_session
reset_session
redirect_to login_path, notice: "Previous session terminated. Please log in again."
end
end

The updated code now includes a check for an existing session when a user attempts to log in. If a session already exists for the user, they are redirected to a new action terminate_previous_session and a flash message is displayed notifying them that they are already logged in from another location. The terminate_previous_session action resets the session, effectively logging the user out of their previous session, and then redirects them to the login page with a notice that their previous session has been terminated.

In addition, the code now includes a session expiration time. When a user logs in, the expires_at key in the session hash is set to the current time plus one hour. This means that if the user does not interact with the application for an hour, their session will automatically expire and they will be logged out. This helps to prevent unauthorized access to the user's account if they forget to log out or leave their computer unattended.

This solution prevents multiple concurrent sessions for the same user and implements session expiration to automatically log out inactive sessions, thus fixing the vulnerability. However, for enhanced security, consider implementing multi-factor authentication.

References