Insecure object reference - User deletion - Ruby

Insecure object reference - User deletion - Ruby

Need

Secure user deletion process and session management

Context

  • Usage of Ruby 2.7.2 as the programming language for development
  • Usage of Rails framework for building web applications

Description

Non compliant code

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

The above code is a Ruby on Rails controller for handling user related actions. The destroy method is used to delete a user from the database. It first finds the user by their id, which is passed in the request parameters, and then calls the destroy method on the user object.

This code is vulnerable to insecure direct object reference (IDOR) because it does not check if the current user has the right to delete the specified user. Any authenticated user can delete any other user just by knowing their id. This can lead to unauthorized deletion of users, leaving the system inoperative.

Moreover, after the user is deleted, the session is not invalidated. This allows the deleted user to continue browsing the application until their session expires naturally. This could lead to further unauthorized actions being performed by the deleted user.

To fix this vulnerability, the application should check if the current user has the right to delete the specified user. Additionally, the session should be invalidated immediately after the user is deleted.

Steps

  • Implement authentication and authorization mechanisms to ensure that only authorized users can delete other users.
  • Validate the user's session before allowing the deletion of a user.
  • Consider implementing a confirmation step before deleting a user to prevent accidental deletions.
  • Update the session management to invalidate the session of a deleted user.

Compliant code

        class UsersController < ApplicationController
  before_action :set_user, only: [:destroy]
  before_action :authenticate_user!
  before_action :authorize_user, only: [:destroy]

  def destroy
    if @user.destroy
      flash[:notice] = "User deleted successfully."
      sign_out @user
    else
      flash[:alert] = "User deletion failed."
    end
    redirect_to root_url
  end

  private

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

  def authorize_user
    unless current_user.admin?
      flash[:alert] = "You are not authorized to perform this action."
      redirect_to root_url
    end
  end
end
        
        

The updated code includes several security measures to prevent insecure object reference vulnerabilities.

1. before_action :set_user, only: [:destroy]
- This line sets the user to be deleted before the destroy action is performed. This ensures that the user exists and can be deleted.

2. before_action :authenticate_user!
- This line ensures that a user is authenticated before they can perform any action. This prevents unauthorized users from deleting users.

3. before_action :authorize_user, only: [:destroy]
- This line ensures that the current user is authorized to delete users. In this case, only admin users are allowed to delete users. This prevents regular users from deleting other users.

4. if @user.destroy
- This line attempts to delete the user. If the deletion is successful, the user is signed out and a success message is displayed. If the deletion fails, an error message is displayed.

5. sign_out @user
- This line signs out the deleted user. This ensures that the user's session is invalidated upon deletion, preventing the user from continuing to browse the application.

6. def authorize_user
- This method checks if the current user is an admin. If not, the user is redirected to the root URL with an error message. This prevents unauthorized users from deleting users.

By implementing these measures, the application is protected against insecure object reference vulnerabilities related to user deletion.

References