Skip to main content

DOM-Based cross-site scripting (XSS)

Need

Prevention of cross-site scripting (XSS) attacks

Context

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

Description

Non compliant code

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

The above code is a simple example of a controller in a Ruby on Rails application. It is vulnerable to DOM-Based cross-site scripting (XSS) due to the lack of input sanitization and validation.

The show method retrieves a user by their ID and then updates the user's name attribute with the value provided in the request parameters. The problem here lies in the fact that the application does not validate or sanitize the params[:name] value before updating the user's name attribute.

This means that an attacker can inject malicious JavaScript code as the name parameter, which will then be stored in the database and rendered in the user's browser whenever the user's name is displayed. This malicious code can steal sensitive information, manipulate web content, or perform any actions that the user can perform.

In the context of DOM-based XSS, the attacker can manipulate the DOM environment in the victim’s browser used by the original client-side script, so that the client-side code runs in an "unexpected" manner. Because the HTTP response itself does not change, the malicious payload cannot be detected by traditional mechanisms that monitor and filter HTTP traffic.

This code vulnerability could lead to serious security implications if not handled properly.

Steps

  • Implement server-side input validation to ensure that user-supplied data is safe and does not contain any malicious code.
  • Use proper output encoding or escaping techniques when displaying user-supplied data to prevent it from being interpreted as HTML or JavaScript code.
  • Avoid using user-supplied data directly in dynamic content generation without proper sanitization.
  • Consider using a Content Security Policy (CSP) to restrict the types of content that can be loaded and executed on the client-side.
  • Regularly update and patch the Ruby on Rails framework and its dependencies to ensure that any known vulnerabilities are addressed.

Compliant code

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

private

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

The original code was vulnerable to DOM-Based Cross-Site Scripting (XSS) because it was directly using user-supplied data (params[:name]) to update a user attribute without any validation or sanitization. This could allow an attacker to inject malicious scripts that would be executed in the browser of any user viewing the affected page.

The fixed code introduces a private method user_params that uses Rails' strong parameters feature to whitelist the :name parameter. This means that only the :name parameter will be permitted for mass assignment in the update method, and any other parameters supplied by the user will be ignored. This helps to prevent mass assignment vulnerabilities.

In addition, the require(:user) call ensures that the parameters must include a :user key. If this key is not present, an ActionController::ParameterMissing error will be raised, which will prevent the update from taking place.

This fix addresses the immediate XSS vulnerability by ensuring that user-supplied data is validated before it is used. However, it is also recommended to implement further measures such as output encoding or escaping, use of a Content Security Policy (CSP), and regular updates and patching of the Rails framework and its dependencies to protect against other potential vulnerabilities.

References