Skip to main content

Stored cross-site scripting (XSS)

Need

Prevention of persistent cross-site scripting (XSS) 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(params[:user])
redirect_to @user
end
end

In the code snippet above, the update action in the UsersController is vulnerable to Stored Cross-Site Scripting (XSS) attacks. The issue lies in the line @user.update_attributes(params[:user]).

This line directly updates the user attributes with the parameters received from the client side. If an attacker sends a request with malicious JavaScript code embedded in the user parameters, this code would be saved to the database. Later, when this data is displayed to other users, the malicious script would be executed in their browsers, leading to a potential compromise of their session data or the spreading of malicious software.

This vulnerability is due to the fact that the application does not sanitize or escape the user input before saving it to the database and rendering it in the browser. This allows an attacker to inject malicious scripts which can be executed in the context of the user's session.

Steps

  • Implement input validation and sanitization to prevent malicious code from being stored in the user fields.
  • Use appropriate encoding or escaping techniques when displaying user input to prevent the execution of injected JavaScript code.
  • Consider using a Content Security Policy (CSP) to restrict the types of content that can be loaded by the application.
  • Regularly update and patch the Ruby on Rails framework and its dependencies to ensure the latest security fixes are applied.
  • Educate developers about secure coding practices and the risks associated with cross-site scripting vulnerabilities.

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 original code was vulnerable to a Stored Cross-Site Scripting (XSS) attack because it directly used the params[:user] hash to update user attributes. This means that an attacker could inject malicious JavaScript code into any of the user fields, which would then be stored in the database and executed whenever the user data is displayed.

The fixed code introduces a new private method user_params that uses Rails' strong parameters feature to whitelist the :name and :email fields. This means that only these fields will be permitted for mass assignment, and any other fields (including any potentially malicious ones) will be filtered out.

This is a form of input validation and sanitization that prevents malicious code from being stored in the user fields. It's important to note that this is just one layer of defense against XSS attacks, and other measures such as output encoding/escaping and Content Security Policies should also be implemented.

Additionally, it's crucial to regularly update and patch the Ruby on Rails framework and its dependencies to ensure the latest security fixes are applied. Developers should also be educated about secure coding practices and the risks associated with cross-site scripting vulnerabilities.

References