HSTS in Rails

Setting up Strict Transport Security in Ruby on Rails 4.

HTTP Strict Transport Security (HSTS) is a recent specification aimed at stopping a certain type of man-in-the-middle attack known as SSL Stripping. By default, when a user types “” into their browser, the browser prefixes that with “http://”. A man-in-the-middle attack can hijack the connection before the server redirect to HTTPS gets back to the browser, spoofing the site and potentially luring the user into providing sensitive data to the attacker.

Rails has a simple configuration setting to enable HSTS when your application already supports SSL. You can activate it by uncommenting the config.force_ssl setting in your `production.rb` environment file. Once deployed this will add the Strict-Transport-Security headers to each request telling the browser all future requests should go over HTTPS. Rails adds an expiry date 1 year in the future and does not add the includeSubDomains part as it doesn't know if all subdomains are served over SSL.

Adding our own header

A year is a bit long for the project I am working on. At the worst, some visitors would have problems accessing our site up to one year when we decide to stop serving over SSL. We could add a max-age=0 for a while and hope most earlier visitors visit the site again which would remove the HSTS cache or every visitor could manually empty their cache but this will cause a lot of work for our helpdesk. Rails also doesn't add HSTS to subdomains out-of-the-box so we rolled our own.

Add the following to your ApplicationController:

before_action :force_ssl, if: -> { Rails.env.production? }

def force_ssl
  response.headers['Strict-Transport-Security'] = 'max-age=2678400; includeSubDomains'
  # 31 days