Insecure or unset HTTP headers - Cache Control - Ruby

Insecure or unset HTTP headers - Cache Control - Ruby

Need

Implementation of secure and appropriate Cache Control headers

Context

  • Usage of Ruby for building dynamic and object-oriented applications
  • Usage of ActionPack for handling web requests and generating responses in a Ruby on Rails application

Description

Non compliant code

        class ApplicationController < ActionController::Base
  # some code here
end
        
        

In the above code, we have a base controller ApplicationController from which all other controllers in the Ruby on Rails application inherit. This controller is missing the HTTP Cache-Control header. This means that all responses from this application will not include this header.

The Cache-Control HTTP header holds directives (instructions) — for both the request and the response — that control who can cache the response, under which conditions, and for how long. Insecure or unset Cache-Control headers can lead to private data being cached in public, shared caches (like a user's browser cache) and increases the risk of unauthorized access to this data.

In this case, without the Cache-Control header, the application's responses can be stored in caches that might not be secure. This could potentially lead to unauthorized access to sensitive information.

Steps

  • Add the Cache Control security header to the response.
  • Set the value of the Cache Control header to a secure value.
  • Ensure that the Cache Control header is properly configured for each response in the application.
  • Test the application to verify that the Cache Control header is being set correctly.
  • Update any relevant documentation or security guidelines to include the requirement of setting the Cache Control header.

Compliant code

        class ApplicationController < ActionController::Base
  before_action :set_cache_headers

  private

  def set_cache_headers
    response.headers["Cache-Control"] = "no-store, no-cache, must-revalidate, post-check=0, pre-check=0"
    response.headers["Pragma"] = "no-cache"
    response.headers["Expires"] = "Mon, 01 Jan 1990 00:00:00 GMT"
  end
  # some code here
end
        
        

The above code fixes the vulnerability by setting the Cache-Control, Pragma, and Expires headers in the HTTP response.

The before_action directive at the top of the ApplicationController ensures that the set_cache_headers method is called before every action in the application. This method sets the Cache-Control header to "no-store, no-cache, must-revalidate, post-check=0, pre-check=0", the Pragma header to "no-cache", and the Expires header to a date in the past.

These settings instruct the client's browser not to store a cached copy of any page from the application. This is important because it prevents sensitive user data from being stored in the cache, where it could potentially be accessed by unauthorized users.

After implementing this fix, it's important to test the application to ensure that the headers are being set correctly. You can do this by inspecting the headers of the HTTP response in your browser's developer tools.

Finally, remember to update any relevant documentation or security guidelines to include the requirement of setting these headers. This will help ensure that the application remains secure as it continues to be developed and maintained.

References