SSL with Rails
So you saw Firesheep and are worried about security in your app? That’s good, you should be. SSL is easy to do and there’s no reason not to these days. Also, the tools are much better than before, so let’s get started.
1. Use SSL all the time
There are two great gems that you can use if you’re on
Rails 2.3+3 or 3.0+. Josh Peek’s Rack::SSL is simple and works well, while Tobias Matthies’ Rack::SslEnforcer has more configuration options. I recommend Rack::SSL unless you need more complexity.
Start by adding the gem dependency, and then add the middleware to your applicable environments:
# Gemfile gem 'rack-ssl'
# config/environments/production.rb require 'rack/ssl' config.middleware.use Rack::SSL
# rails 3.x config.middleware.insert_before ActionDispatch::Cookies, Rack::SSL # Rails 2.3.x config.middleware.insert_after ActionController::Failsafe, Rack::SSL
# config/application.rb config.force_ssl = true
Both gems do the same few things:
- Redirects all traffic to the https equivalent
- Marks all cookies as secure1
- Uses Strict Transport Security (HSTS) which helps enforce SSL in modern browsers.
The secure cookies are a big win, but it won’t change existing cookies, like your session cookie. An easy fix is to simply rename your session cookie in
config/initializers/session_store.rb. I typically just add the word “secure” to the key.
MyApp::Application.config.session_store :cookie_store, :key => '_my-app_secure_session'
2. Avoid Mixed Content Warnings
Here’s the deal: you cannot have any non-SSL assets on an SSL page. None.
If you’re not putting the hostname in your assets, then you’ll be fine already. 3rd-party code is where you can get into trouble. For example, if you’re pulling in jQuery from Google’s CDN, this code will break:
Instead, use protocol-relative paths, which are not widely known but work perfectly2:
Test your site using Chrome. It has the best warnings, and you may miss them in other browsers like my beloved Safari.
3. Know Your Hostnames
Make sure you know what hostname(s) you’re serving from as your certificate will either be tied to a specific host (www.example.com vs. example.com) or you’ll have a wildcard certificate (*.example.com) that will work for one level of subdomains. If you put your users in a situation where they’re sent to a host without a certificate and redirected to one that is, they may see a warning.
Fix this by only linking to known secure domains (or link to the insecure one with a proper redirect) and tell Google of your preferred domain.
That’s it. If you’re doing these three things, then you’re most of the way to security. At least now you can focus on the code you write and stop worrying about SSL. For additional info, the EFF has a good overview of deploying HTTPS.
1 But not existing cookies. Don’t skip that part.
3 Use caution with Rails 2.3. We just ran into a confusing bug because Rails 2.3.10 is broken and makes cookies an array, not a string. I have a branch of Josh’s Rack::SSL that fixes that issue. but the real solution is to fix Rails.