Skip to main content

Cached form fields

Need

Prevention of sensitive information leakage through cached form fields

Context

  • Requirement of Ruby 2.0 or higher for running the application
  • Usage of Rails framework for building web applications

Description

Non compliant code

class UsersController < ApplicationController
def new
@user = User.new
end

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(:name, :email, :password, :password_confirmation)
end
end

This code is a standard implementation of a form in a Ruby on Rails application. It creates a new User object and then saves it to the database if the input is valid. The form fields are not explicitly disabled from being cached by the browser.

The vulnerability lies in the fact that sensitive information such as name, email, password, and password confirmation are not protected from caching. This means that if a user fills out this form and then leaves the page without submitting, the form data can be stored in the browser's cache. This cached data can then potentially be accessed by an attacker, who could use it for malicious purposes.

This vulnerability is especially concerning for shared or public computers, where multiple users might use the same browser. If one user enters sensitive information into the form and then leaves the page without submitting, the next user could potentially retrieve this information from the cache.

In this particular code, the vulnerability could be exploited to gain unauthorized access to user accounts, as it exposes both the email (which is often used as a username) and the password. This could lead to data breaches and other security incidents.

Steps

  • Disable caching of input fields in the application
  • Add the 'autocomplete' attribute to form fields and set it to 'off'
  • Use secure HTTP headers to prevent caching of sensitive information
  • Implement CSRF protection to prevent cross-site request forgery attacks

Compliant code

class UsersController < ApplicationController
before_action :set_cache_buster

def new
@user = User.new
end

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(:name, :email, :password, :password_confirmation)
end

def set_cache_buster
response.headers["Cache-Control"] = "no-cache, no-store, max-age=0, must-revalidate"
response.headers["Pragma"] = "no-cache"
response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT"
end
end

The updated code includes a before_action callback set_cache_buster that is called before every action in the UsersController. This method sets HTTP headers to prevent the browser from caching the response.

The Cache-Control header is set to no-cache, no-store, max-age=0, must-revalidate which tells the browser not to cache the response. The Pragma header is set to no-cache which is a fallback for HTTP/1.0 clients. The Expires header is set to a date in the past, telling the browser that the response is already expired and should not be cached.

This will prevent the caching of form fields and sensitive information in the browser's cache, mitigating the risk of information leakage.

Please note that this is a server-side solution. For a complete solution, you should also set the autocomplete attribute to off on the form fields in your views to instruct the browser not to cache input values.

References