Lack of data validation - Web Service - Ruby

Lack of data validation - Web Service - Ruby

Need

Implementation of robust data validation and input sanitization mechanisms

Context

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

Description

Non compliant code

        class UsersController < ApplicationController
  def create
    @user = User.new(params[:user])
    if @user.save
      redirect_to @user
    else
      render 'new'
    end
  end
end
        
        

The above code is a typical Ruby on Rails controller action for creating a new user. The params[:user] is a hash that includes all the user-related data sent from the client side.

However, this code is vulnerable due to lack of data validation. It directly takes user input from params[:user] and uses it to create a new User object. This allows an attacker to send any data they want, including special characters or oversized data, which can lead to various attack vectors such as SQL injection, XSS (Cross Site Scripting), or even Denial of Service (DoS) if the data is too large.

For example, an attacker could send a username with SQL commands, or a bio that is several gigabytes in size. The server would then try to process this data and insert it into the database, leading to potential SQL injection or server overload.

The lack of data validation and control over the size of the fields being sent to the server makes this code insecure.

Steps

  • Implement server-side data validation to ensure that only valid data is accepted.
  • Sanitize user input to prevent the use of special characters that can be used for malicious purposes.
  • Implement size restrictions on the fields to prevent excessive data from being sent to the server.
  • Use strong parameters or a similar mechanism to whitelist and validate the parameters being used in the create action.
  • Consider implementing input validation at the client-side as an additional layer of defense.

Compliant code

        class UsersController < ApplicationController
  def create
    @user = User.new(user_params)
    if @user.save
      redirect_to @user
    else
      render 'new'
    end
  end

  private

  def user_params
    params.require(:user).permit(:username, :email, :password).tap do |whitelisted|
      whitelisted[:username] = sanitize(whitelisted[:username])
      whitelisted[:email] = sanitize(whitelisted[:email])
      whitelisted[:password] = sanitize(whitelisted[:password])
    end
  end

  def sanitize(field)
    ActionController::Base.helpers.sanitize(field)
  end
end
        
        

The updated code now includes a private method user_params which uses Rails' strong parameters to whitelist and validate the parameters being used in the create action. This ensures that only the :username, :email, and :password fields are permitted, and any additional fields sent in the request will be ignored.

The user_params method also sanitizes the input for these fields using the sanitize method. This method uses Rails' built-in ActionController::Base.helpers.sanitize method to strip out any potentially harmful HTML tags or attributes from the input. This helps to prevent attacks such as Cross-Site Scripting (XSS).

The sanitize method is called using the tap method on the whitelisted parameters. This allows us to modify the whitelisted parameters in-place, ensuring that the sanitized values are used when creating the new User.

Finally, the create action now uses user_params instead of params[:user] when creating the new User. This ensures that only the whitelisted and sanitized parameters are used, providing an additional layer of security.

This code does not implement size restrictions on the fields. This would need to be done at the model level, using Rails' built-in validations. For example, you could add validates :username, length: { maximum: 50 } to the User model to ensure that the username is no more than 50 characters long.

References