logo

Insecure or unset HTTP headers - Strict Transport Security - Ruby


Need

Enforcement of Strict Transport Security (HSTS) headers


Context

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

Description

Insecure Code Example

# 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

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

Secure Code Example

# 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

  • 131 - Insecure or unset HTTP headers - Strict Transport Security

  • Last updated

    2023/09/18