Cross-site request forgery - Ruby

Cross-site request forgery - Ruby

Need

Protection against cross-site request forgery attacks

Context

  • Usage of Ruby 2.0+ for developing Ruby applications
  • Usage of Rails framework for building web applications

Description

Non compliant code

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

  private
    def user_params
      params.require(:user).permit(:name, :email)
    end
end
        
        

The above code shows a typical update action in a Ruby on Rails controller. In this case, it's the UsersController, which is responsible for updating user data. The update method finds a user in the database using the ID passed in the request parameters, then updates the user's attributes using the parameters from the request.

The vulnerability here is that there is no check to ensure that the request is legitimate and is actually coming from the authenticated user. This leaves the application open to Cross-Site Request Forgery (CSRF) attacks. In a CSRF attack, an attacker tricks an authenticated user into executing actions without their consent. In this case, an attacker could trick a user into sending a request to this update action, causing the user's data to be changed without their knowledge or consent.

This vulnerability can be exploited if an attacker can predict the structure of the request (which is often not difficult in a RESTful application like a typical Rails app) and can trick an authenticated user into clicking a link or loading a page that sends such a request. The application would then process the request as if it were legitimate, leading to unauthorized changes.

The lack of CSRF protection in this code is a serious security flaw. Rails does have built-in CSRF protection, but it needs to be explicitly enabled in the application's configuration. In this case, it appears that CSRF protection has not been enabled, leaving the application vulnerable.

Steps

  • Implement Cross-Site Request Forgery (CSRF) protection in the application.
  • Use CSRF tokens to validate the authenticity of requests.
  • Ensure that the CSRF token is included in all forms and requests that modify data.
  • Verify the CSRF token on the server-side before processing any sensitive actions.
  • Use the built-in CSRF protection mechanisms provided by the Ruby on Rails framework.
  • Enable the `protect_from_forgery` method in the ApplicationController to automatically add CSRF protection to all controllers.
  • Consider using the `form_with` helper in views to generate forms with CSRF protection.
  • Regularly update the Ruby on Rails framework to benefit from the latest security patches and improvements.

Compliant code

        class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception
end

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

  private
    def user_params
      params.require(:user).permit(:name, :email)
    end
end
        
        

The updated code includes the protect_from_forgery with: :exception directive in the ApplicationController class. This directive enables CSRF protection for all controllers that inherit from ApplicationController, including UsersController.

The protect_from_forgery method generates a unique CSRF token for every session. This token is embedded in all forms and AJAX requests generated by Rails. When a form is submitted or an AJAX request is made, Rails will automatically include the CSRF token as a parameter. On the server side, Rails will compare the token received with the one that was generated for the session. If the tokens match, the request is allowed to proceed. If they don't match, Rails will raise an exception and the request will be denied.

This mechanism ensures that only forms and AJAX requests that were generated by the application can be used to perform actions in the application. An attacker cannot forge a request because they cannot know the CSRF token for the session.

In the views, use the form_with helper to generate forms. This helper automatically includes the CSRF token as a hidden field in the form.

                <%= form_with(model: @user, local: true) do |form| %>
  <!-
- form fields here --> <% end %>


Regularly update the Ruby on Rails framework to benefit from the latest security patches and improvements. This will help to ensure that the CSRF protection mechanism is as robust as possible.

References