Skip to main content

Insecure session management

Need

Secure session management

Context

  • Usage of Ruby 2.5.0 as the programming language for development
  • Usage of Ruby on Rails for building web applications

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

def destroy
session[:user_id] = nil
redirect_to root_url, notice: "Logged out!"
end
end

In this Ruby on Rails application, a session is created when a user logs in. The user's ID is stored in the session object, which is a hash that Rails provides to track data over multiple requests from the same user. When a user logs out, their user ID is simply set to nil in the session hash.

However, this code does not properly manage the session token. The session token is not expired or invalidated when the user logs out. This means that if an attacker were to gain access to a session token, they could use it to make requests on behalf of the user even after the user has logged out. This is a significant security vulnerability, as it could allow an attacker to impersonate a user and perform actions on their behalf. This type of attack is known as session hijacking or session sidejacking.

Steps

  • Implement session expiration mechanism
  • Set an expiration time for the session token
  • Invalidate the session token when the user logs out
  • Use secure session storage mechanism
  • Encrypt the session token to prevent tampering
  • Implement session token regeneration after login

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
session[:expires_at] = Time.current + 2.hours
redirect_to root_url, notice: "Logged in!"
else
flash.now.alert = "Email or password is invalid"
render "new"
end
end

def destroy
session[:user_id] = nil
session[:expires_at] = nil
redirect_to root_url, notice: "Logged out!"
end

private

def check_session_expiration
if session[:expires_at] && session[:expires_at] < Time.current
session[:user_id] = nil
session[:expires_at] = nil
flash[:alert] = "Your session has expired. Please log in again."
redirect_to login_url
end
end
end

The updated code now includes a session expiration mechanism. When a user logs in, an expiration time is set for the session token (session[:expires_at] = Time.current + 2.hours). This means that the session will automatically expire 2 hours after it was created, even if the user does not manually log out.

In the destroy method, which is called when a user logs out, the session token and its expiration time are both set to nil. This invalidates the session token, so it can no longer be used to post requests.

A new private method check_session_expiration is added to check if the session has expired every time a request is made. If the session has expired, the user is logged out and redirected to the login page with a flash message informing them that their session has expired.

This code does not yet include secure session storage, session token encryption, or session token regeneration after login. These features would require additional changes to the application's configuration and possibly the use of additional gems.

References