Insecure or unset HTTP headers - Strict Transport Security - Ruby

Insecure or unset HTTP headers - Strict Transport Security - Ruby

Need

Enforcement of Strict Transport Security (HSTS) headers

Context

  • Usage of Ruby 2.0+ for Ruby programming language version compatibility
  • Usage of Ruby for building dynamic and object-oriented applications
  • Usage of Rails framework for building web applications

Description

Non compliant code

        # app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_action :set_headers

  private

  def set_headers
    response.headers['X-Frame-Options'] = 'SAMEORIGIN'
    response.headers['X-XSS-Protection'] = '1; mode=block'
    response.headers['X-Content-Type-Options'] = 'nosniff'
    # Missing Strict-Transport-Security header
  end
end
        
        

This code is from a Ruby on Rails application, specifically the ApplicationController which is the main controller from which all other controllers in the application inherit.

The before_action :set_headers line ensures that the set_headers method is called before every action in every controller.

The set_headers method itself is setting several important HTTP security headers. X-Frame-Options is set to 'SAMEORIGIN' to prevent clickjacking attacks, by ensuring that the content can only be framed by pages on the same domain. X-XSS-Protection is set to '1; mode=block' to enable XSS filtering. If a cross-site scripting attack is detected, rather than sanitizing the page, the browser will prevent rendering of the page. X-Content-Type-Options is set to 'nosniff' to prevent the browser from MIME-sniffing a response away from the declared content-type.

However, the Strict-Transport-Security header is missing. This header is used to enforce secure (HTTP over SSL/TLS) connections to the server. This makes it more difficult for hackers to downgrade the connection to a less secure version. Without this header, even if your site supports HTTPS, a user could potentially end up communicating over an insecure HTTP connection.

Steps

  • Add the Strict-Transport-Security header to the response headers.
  • Set the value of the Strict-Transport-Security header to include the 'max-age' directive with a sufficiently long duration.
  • Ensure that the Strict-Transport-Security header is only sent over HTTPS connections.
  • Consider including the 'includeSubDomains' directive in the Strict-Transport-Security header if applicable.

Compliant code

        # app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_action :set_headers

  private

  def set_headers
    response.headers['X-Frame-Options'] = 'SAMEORIGIN'
    response.headers['X-XSS-Protection'] = '1; mode=block'
    response.headers['X-Content-Type-Options'] = 'nosniff'
    response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains' # Added Strict-Transport-Security header
  end
end
        
        

The updated code includes the Strict-Transport-Security HTTP header in the response headers. This header is a security feature that helps protect the website against man-in-the-middle attacks by enforcing the use of HTTPS.

The value of the Strict-Transport-Security header has been set to 'max-age=31536000; includeSubDomains'. This means that the browser should remember for 31536000 seconds (approximately one year) that this site should only be accessed using HTTPS. The includeSubDomains directive indicates that this rule applies to all subdomains as well.

Please note that the Strict-Transport-Security header should only be sent over HTTPS connections. If your application also serves HTTP connections, you should add a condition to only add this header for HTTPS requests.

This change helps to mitigate the risk of insecure or unset HTTP headers, enhancing the overall security of the application.

References