Lack of data validation - Host Header Injection - Ruby

Lack of data validation - Host Header Injection - Ruby

Need

Implementation of proper data validation and sanitization for the host header input

Context

  • Usage of Ruby for building web applications and scripting
  • Usage of ActionController for handling actions and requests in a Ruby on Rails application

Description

Non compliant code

        class ApplicationController < ActionController::Base
  def redirect_to_dashboard
    redirect_to params[:url]
  end
end
        
        

In the above code, the redirect_to_dashboard method in ApplicationController is redirecting the user to a URL which is being received from the client side in the form of a parameter. This is a security vulnerability known as Host Header Injection.

The params[:url] is directly being used in the redirect_to method without any sort of validation or sanitization. An attacker can manipulate this params[:url] to redirect the user to a malicious website. This can lead to phishing attacks, stealing of user sensitive data and spreading of malware.

This issue occurs because the application trusts and uses the user input directly without validating it. This is a common issue in many web applications and is a serious security concern.

Steps

  • Implement proper input validation and sanitization for the 'url' parameter.
  • Validate that the 'url' parameter is a valid URL before redirecting.
  • Use a whitelist approach to only allow specific domains or URLs to be redirected to.
  • Avoid using user-supplied data directly in the redirect_to method.
  • Consider using a safer alternative to the redirect_to method that provides additional security checks.
  • Regularly update and patch the Ruby on Rails framework to benefit from the latest security enhancements.

Compliant code

        class ApplicationController < ActionController::Base
  def redirect_to_dashboard
    url = params[:url]
    if url.present? && valid_url?(url) && whitelisted_url?(url)
      redirect_to url
    else
      # Handle invalid url case
      flash[:error] = "Invalid URL"
      redirect_to root_path
    end
  end

  private

  def valid_url?(url)
    uri = URI.parse(url)
    uri.kind_of?(URI::HTTP) || uri.kind_of?(URI::HTTPS)
  rescue URI::InvalidURIError
    false
  end

  def whitelisted_url?(url)
    # Add your whitelisted domains here
    whitelisted_domains = ["www.example.com", "example.com"]
    uri = URI.parse(url)
    whitelisted_domains.include?(uri.host)
  rescue URI::InvalidURIError
    false
  end
end
        
        

The updated code now includes two private methods valid_url? and whitelisted_url? to validate the 'url' parameter before redirecting.

The valid_url? method checks if the 'url' parameter is a valid HTTP or HTTPS URL. It uses the URI.parse method to parse the 'url' and checks if it is an instance of URI::HTTP or URI::HTTPS. If the 'url' is not a valid URL, URI.parse will raise an URI::InvalidURIError exception, which is rescued and returns false.

The whitelisted_url? method checks if the host of the 'url' is included in the list of whitelisted domains. It uses the URI.parse method to parse the 'url' and get the host. If the host is included in the whitelisted domains, it returns true. If the 'url' is not a valid URL, URI.parse will raise an URI::InvalidURIError exception, which is rescued and returns false.

In the redirect_to_dashboard method, it first checks if the 'url' parameter is present and if it is a valid and whitelisted URL before redirecting. If the 'url' is not valid or not whitelisted, it sets a flash error message and redirects to the root path.

References