Skip to main content

Insecure object reference

Need

Secure and robust object reference management

Context

  • Usage of Ruby 2.5.0 as the programming language for development
  • Usage of Rails framework for building web applications
  • Usage of ActiveRecord for Object-Relational Mapping (ORM) in database operations

Description

Non compliant code

class UsersController < ApplicationController
def show
@user = User.find(params[:id])
end
end

In the above code, we have a method show within the UsersController class that is used to display the details of a user. The user instance is fetched using User.find(params[:id]) which takes the id from the URL parameters.

This is insecure because an attacker can modify the id parameter in the URL to access the data of another user. This is known as an Insecure Direct Object Reference (IDOR) vulnerability. This happens because the system's authorization mechanism does not prevent one user from accessing another user's data by modifying the id value that identifies it.

For example, if the URL is http://example.com/users/1, an attacker could change it to http://example.com/users/2 to access the second user's information if there are no proper authorization checks in place.

Steps

  • Implement proper authorization checks to ensure that a user can only access their own data.
  • Use a session-based authentication mechanism to authenticate and identify the current user.
  • Ensure that the user's ID or any other sensitive information is not exposed in the URL or any other client-side visible location.
  • Validate the user's access rights before retrieving or modifying any data.
  • Implement access control mechanisms, such as role-based access control (RBAC) or attribute-based access control (ABAC), to enforce fine-grained permissions.
  • Regularly review and update the authorization mechanisms to address any new vulnerabilities or changes in the application's requirements.

Compliant code

class UsersController < ApplicationController
before_action :authenticate_user!
before_action :correct_user, only: [:show]

def show
@user = User.find(params[:id])
end

private

def correct_user
@user = User.find(params[:id])
redirect_to(root_url) unless current_user?(@user)
end

def current_user?(user)
user == current_user
end
end

The updated code now includes two before_action filters at the top of the UsersController class.

The authenticate_user! method is a Devise helper method that ensures a user is signed in before they can access the action. If a user is not signed in, they will be redirected to the sign-in page.

The correct_user method is a new method that we've defined in the private section of the UsersController. This method retrieves the user from the database using the ID parameter and checks if this user matches the currently signed in user. If they do not match, the method redirects the user to the root URL. This ensures that a user can only access their own data.

The current_user? method is another new method that we've defined. This method simply checks if the given user matches the currently signed in user.

With these changes, we have implemented proper authorization checks to ensure that a user can only access their own data. This fixes the insecure direct object reference vulnerability in the original code.

References