Collective Idea

Collective Idea Logo

Daniel Morrison

SSL with Rails

By Daniel Morrison on November 29, 2010 in deployment, https, rails, and ssl

Update: Rails 3.1 bakes this in, so I’ve updated the instructions below to show that.

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

Update: Josh Peek points out in the comments that if you want your session cookie to get automatically secured (yes please), stick the middleware above the session:

# rails 3.x
config.middleware.insert_before ActionDispatch::Cookies, Rack::SSL
# Rails 2.3.x
config.middleware.insert_after ActionController::Failsafe, Rack::SSL

If you’re using Rails 3.1, it builds in support for Rack::SSL. Use this instead:

# config/application.rb
config.force_ssl = true

Both gems do the same few things:

  1. Redirects all traffic to the https equivalent
  2. Marks all cookies as secure1
  3. 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:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js" type="text/javascript"></script>

Instead, use protocol-relative paths, which are not widely known but work perfectly2:

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js" type="text/javascript"></script>

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.

2 CSS files get double-downloaded in IE.

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. Update: Rails 2.3.11 includes the fix. Yay!

By Daniel Morrison on November 29, 2010 in deployment, https, rails, and ssl

53 Comments

  1. Steve Richert

    Steve Richert November 29, 2010 http://oneraceatatime.org/

    Great overview! Protocol-relative paths are certainly news to me. Very cool. Thanks for the suggestions!

  2. John Nunemaker

    John Nunemaker November 29, 2010 http://orderedlist.com

    Interesting. Thanks for sharing!

  3. Michael van Rooijen

    Michael van Rooijen November 29, 2010 http://michaelvanrooijen.com/

    I was just about to look into some security measures I could take. Thanks for sharing! This’ll save me some research time. : )

  4. Mark Cahill

    Mark Cahill November 29, 2010 http://www.tiemonster.info/

    There may be at least one reason not to use SSL. There is some overhead with SSL that may be unacceptable in high-traffic applications. In some situations, the best solution is to only use SSL on server calls which require the transport of sensitive information (ie. authentication), and serve the rest of the traffic over good ol’ HTTP.

  5. Daniel Morrison

    Daniel Morrison November 29, 2010 http://collectiveidea.com

    Mark Cahill: There is an overhead, but this post about Google’s experience made me rethink that stance.

    In short, it was only 1% of CPU usage. I think we can all afford to use SSL for apps where security is important.

  6. Fletcher Nichol

    Fletcher Nichol November 29, 2010 http://github.com/fnichol

    Excellent, I’ve been looking at how to easily mark a cookie as secure in rails. Gotta love the middleware.

  7. Glenn Gillen

    Glenn Gillen November 30, 2010 http://glenngillen.com

    I’ve taken the approach of forcing the redirect at the web server level (i.e., nginx) to ensure that all assets, rack apps, and anything else is always served over SSL. Avoids any risk of mixed content warnings, although you should still fix any protocol specific URLs.

  8. Derek Anderson

    Derek Anderson November 30, 2010 http://armyofevilrobots.com/

    There are bugs in the implementation of protocol relative paths on IE7/8 which result in css being loaded twice if you use either or @import stylesheets. Construct your css with that in mind.

  9. Mark Cahill

    Mark Cahill November 30, 2010 http://www.tiemonster.info/

    Daniel Morrison: That’s only true if the hardware you’re using has encryption built into the CPU instruction set, which should be the case for most modern Intel chips. Hardware acceleration of SSL encryption would certainly reduce the load on the CPU, and really wasn’t something I had ever thought of before…

  10. Nathaniel Bibler

    Nathaniel Bibler November 30, 2010 http://www.nathanielbibler.com/

    It’s worth mentioning that there are SSL certificates available which are not, strictly speaking, wild card certificates, but still cover both www and non-www hostnames. Multi-domain certificates do exist, too. For example, GeoTrust’s QuickSSL Premium will cover up to three subject alternative names (SANs) by default without being a wild card and still remaining relatively inexpensive. Or, other multi-domain options cover 5, 10, 20, etc on a single certificate.

  11. satan

    satan November 30, 2010

    dude, your site looks like shit in small dimensions.  testing dude.  testing.  

  12. Steve

    Steve November 30, 2010

    Mark Cahill: Actually, the overhead has much more to do with how long-lived sessions are.  The bulk transport encryption of SSL is virtually free on today’s hardware, the only overhead is the session setup. It has both public key crypto and increased round trips with added latency, both of which do consume resources.  After the initial handshake, you use session resumption to avoid these costs.If you run a site like gmail where most traffic is returning users, you’ll probably see very little impact. If you only ever get one request per each IP per day, SSL will probably have fairly high overhead. Most sites will be somewhere in the middle, but probably lower overhead then they expect.

  13. Ryan Bigg

    Ryan Bigg November 29, 2010 http://ryanbigg.com

    Brilliant, thanks for the wonderful insight Daniel!

  14. mikhailov

    mikhailov November 30, 2010 http://railsgeek.com

    there is a way to let httpd/nginx redirects all traffic to the https equivalent.
    this way I do - https://gist.github.com/711913

  15. Josh Peek

    Josh Peek December 01, 2010

    If you insert the SSL middleware above the session middleware, it will mark those cookies as secure too.

        config.middleware.insert_after ActionController::Failsafe, Rack::SSL

  16. Daniel Morrison

    Daniel Morrison December 01, 2010 http://collectiveidea.com

    Josh Peek: Thanks for that. I updated the post to mention that. It had been on my list to look into.

    I did find an issue with your plugin on Rails 2.3.10 that I hadn’t seen before. Dropped a branch in our fork.

  17. Daniel Morrison

    Daniel Morrison December 01, 2010 http://collectiveidea.com

    Josh Peek points out that my issue with Rails 2.3.10 is actually a bug in Rails from this commit. Thanks for the heads-up!

  18. Chris

    Chris December 02, 2010

    Will this work correctly in IE6? 

  19. Daniel Morrison

    Daniel Morrison December 03, 2010 http://collectiveidea.com

    Chris: Yep, IE6 can handle protocol-relative URLs fine. Just note my caveat about CSS files getting downloaded twice.

  20. Brett

    Brett December 07, 2010

    nice post. My app is on Heroku, with a SSL cert for www.mysite.com

    If you load
    https://www.mysite.com or http://mysite.com it all redirects correctly w/o error.

    BUT if you load: https://mysite.com
    No redirect happens, and bec of the SSL cert the browser displays a huge SSL not trusted warning.

    I haven’t been able to figure out how to redirect from https://mysite.com to  https://www.mysite.com before the browser SSL warning is displayed?

    I’ve tried a config.middleware.use “Www” as follows but no luck. Any ideas?

    class Www  def initialize(app)    @app = app  end  def call(env)    if env[‘SERVER_NAME’] =~ /^www\./      @app.call(env)    else      [ 307, { ‘Location’ => ‘https://www.companyline.com/’ }, ’’ ]    end  endend

    Thanks for any tips / help.

  21. Brett

    Brett December 07, 2010

    nice post. My app is on Heroku, with a SSL cert for www.mysite.com

    If you load
    https://www.mysite.com or http://mysite.com it all redirects correctly w/o error.

    BUT if you load: https://mysite.com
    No redirect happens, and bec of the SSL cert the browser displays a huge SSL not trusted warning.

    I haven’t been able to figure out how to redirect from https://mysite.com to  https://www.mysite.com before the browser SSL warning is displayed?

    I’ve tried a config.middleware.use “Www” as follows but no luck. Any ideas?

    class Www  def initialize(app)    @app = app  end  def call(env)    if env[‘SERVER_NAME’] =~ /^www\./      @app.call(env)    else      [ 307, { ‘Location’ => ‘https://www.companyline.com/’ }, ’’ ]    end  endend

    Thanks for any tips / help.

  22. Daniel Morrison

    Daniel Morrison December 07, 2010 http://collectiveidea.com

    Brett: the simple answer is that you can’t.

    Even a redirect is considered content, so browsers will expect a certificate. Your best bet is to use a certificate that covers both domains, or a wildcard certificate (*.example.com which works for example.com too).

    I actually setup a site on Heroku just like you did the other day, with similar results. Without a certificate covering the root domain, you get an error.

    I’m doing something similar to you, but in my application_controller.

    Unless there’s a trick I don’t know about, your only option is to get a different certificate. 

    Optionally, you could have the root domain not respond on https. That way it won’t display the security error. If they go to it via http, you redirect them to www.

    Good luck!

  23. Dave

    Dave December 08, 2010

    Daniel, thanks for the insight.  I’ve been into rails for a couple years now, but I’m new to SSL (haven’t been insightful enought to use it yet).  But the time has come :)  Being a newb, can I use ‘rack-ssl’ in place of ‘ssl_requirement’ to route web traffic to https, or do I need to use the two together?  ssl_requirement seems to be more comprehensive in customizing which views need SSL, but I can’t get it to work with my Rails 3 app – i.e. looking for an alternative.

    I got redirected here from http://www.themomorohoax.com/ which recommended your article as an update.

    Dave

  24. Daniel Morrison

    Daniel Morrison December 08, 2010 http://collectiveidea.com

    Dave: rack-ssl can be used as a replacement for ssl_requirement, but the two are a bit different. 

    ssl_requirement lives in your controllers, so it is tied to the app. It gives you more flexibility about when to require ssl, but as Firesheep points out, if you have your session cookie float between https and http, you may be at risk.

    rack-ssl, while giving you some control really lets you lock the whole app down. You can set limited exceptions, but really it is meant to make the whole site SSL

    If you’re going all SSL, rack-ssl is far superior. If you need it only some of the time, ssl_requirement is better (but you may expose yourself to firesheep risks if you’re not careful). 

    I’d recommend going all in.

  25. Dave

    Dave December 09, 2010

    Thanks Daniel!  More great information….one more question:  Regarding Josh’s update, do you add that to the production.rb environment change we’ve already made, does it replace it (see below), or does it go somewhere else (like in application.rb)?

    1. config/environments/production.rbrequire ‘rack/ssl’## config.middleware.use Rack::SSL
    2. replaced by…..
    3. rails 3.x (or does it go somewhere elseconfig.middleware.insert_before ActionDispatch::Cookies, Rack::SSL

    Thanks again :)
    Dave

  26. Daniel Morrison

    Daniel Morrison December 09, 2010 http://collectiveidea.com

    Dave: It replaces it. The config.middleware.insert_before is instead of config.middleware.use

  27. Randy

    Randy December 09, 2010

    Dan is right, you do not need to include the extra original call

  28. Dom

    Dom December 09, 2010 http://meetdom.com

    Great post – thanks!  I’ll be setting up a wildcard SSL in the next week, so your post on this is very timely.  The ImperialViolet article was very enlightening too.

    Is there something special I need to do to ensure the root domain is included in the wildcard SSL, perhaps something I need to specify in the CSR? I’m considering a RapidSSL Wildcard SSL Certificate from certs4less.com.

  29. Daniel Morrison

    Daniel Morrison December 09, 2010 http://collectiveidea.com

    Dom: you’re welcome!  

    On the wildcard, it is typical that it covers the root and one level of subdomains. So example.com and *.example.com.

    Double-check before you buy though. I don’t buy them often enough to know what all the companies do. 

  30. Rob Shedd

    Rob Shedd December 12, 2010 http://blog.shedd.us

    Has anyone run into issues getting Rails 2.3.x to boot up with this configuration change?

    After inserting into my production.rb environment configuration as shown:

    require ‘rack/ssl’config.middleware.insert_after ActionController::Failsafe, Rack::SSL

    I kept getting 

    uninitialized constant Rails::Rack::SSL
    I’m using Bundler, so I first assumed that I needed to install the gem manually.  However, doing so didn’t resolve the issue.

    Putting Rack::SSL in quotes seems to allow it to run, though:

    require ‘rack/ssl’config.middleware.insert_after ActionController::Failsafe, ‘Rack::SSL

    Any idea why this might be?  Any functionality affected by making this change?

    Thanks!

  31. Daniel Morrison

    Daniel Morrison December 13, 2010 http://collectiveidea.com

    Rob Shedd: You should be fine. We’re using it on 2.3 with success.

    If you move it to environment.rb does it work? There is a load order difference. 

  32. Alex

    Alex December 15, 2010 http://www.shamne.com

    Just started searching some info about using ssl with rails, and found this post, thanks Daniel for good advices i’ll use this in my next project.

  33. Ben

    Ben January 24, 2011 http://benjamincoppock.com

    I’m trying to get SSL going for all page requests, but ONLY on condition a user is logged in (or logging in, etc.) — I happen to be using AuthLogic.

    Any suggestions?

  34. Daniel Morrison

    Daniel Morrison January 24, 2011 http://collectiveidea.com

    Ben: you really won’t be able to do that. 

    SSL happens at a lower level; the entire request is secured, so by the time you get to the controller you can’t do anything.

    You could enable SSL for only certain paths (see the ssl_requirement plugin) but I recommend against that. Unless you use a 2nd cookie (like GitHub did at first) you open yourself up to vulnerabilities. This is exactly the kind of hack that Firesheep exposed.

    I’d ask why you don’t want SSL on the other requests. There really aren’t good reasons to not anymore. Use SSL everywhere.

  35. Marcus Ahnve

    Marcus Ahnve February 08, 2011 http://marcusahnve.org

    I get a endless redirect loop trying to use rack-ssl, both on Apache and Nginx. Thankful for any help as to what I am doing wrong

  36. Daniel Morrison

    Daniel Morrison February 08, 2011 http://collectiveidea.com

    Marcus Ahnve: do you have any old ssl_requirement stuff hanging around? Any other redirects that are including http?

  37. Kevin

    Kevin February 10, 2011 http://www.mbioex.com

    Footnote 3 is fixed now that 2.3.11 was released 2/8/2011. The commit:

    https://github.com/rails/rails/commit/e0eb8e9c65ededce64169948d4dd51b0079cdd10

  38. Daniel Morrison

    Daniel Morrison February 13, 2011 http://collectiveidea.com

    @Kevin: Good point. I’ve updated the footnote. Thanks!

  39. Pieter Demoor

    Pieter Demoor February 15, 2011

    I also get an endless redirect loop with rack-ssl. I’m using apache, rails version 3.0.3 and ruby 1.9.2p0.

    I’ve tried almost every gem out there and i’ve made sure that i removed everything from the previous gems and so called solutions. In my application i used the default redirect helpers so I have no clue why i keep getting these endless redirects.

    I will now try to test it with a fresh app. Hope it works

  40. Jason Green

    Jason Green February 15, 2011 http://www.dynamic50.com

    Great post. We have just done a writeup for SSL using wildcard subdomains and Godaddy & Heroku here:
    http://blog.dynamic50.com/2011/02/15/ssl-on-wildcard-domains-on-heroku-using-godaddy/

  41. Tom

    Tom February 17, 2011 http://www.venombytes.com

    For Rob Shedds issue, i was having the same problem on Rails 2.3.11,

    But ensuring a :: prefix solves that,
    eg.
    config.middleware.use ::Rack::SSL
    not
    config.middleware.use Rack::SSL

  42. Richard

    Richard March 02, 2011 http://about.me/richardworrall

    Thanks for the link to SSL Enforcer.. what a gem (pun intended)!

  43. Nico

    Nico March 16, 2011 http://railstoolkit.com

    Thanks for this, rack-ssl works fine for me. However, just like Ben I would like to only force ssl when the user is logged in. You say it’s not possible. However, I don’t see why not. Can’t I just redirect to the ssl version of the page in a before_filter at the controller level if the user is logged?

  44. DHH

    DHH March 27, 2011

    Rails 3.1 will now have force_ssl baked in at both the app and controller level. 

    App-level: https://github.com/rails/rails/commit/2c0c4d754e34b13379dfc53121a970c25fab5dae

    Controller-level: https://github.com/rails/rails/commit/7cbdfa83035aacb0d4dbfa84525b54e9122efb75

  45. Kevin Monk

    Kevin Monk July 08, 2011 http://www.mangoswiss.com

    If you’re having problems with the infinite redirects then you might want to try adding…

    RequestHeader set X-Forwarded-Proto “https”

    to your vhost.conf file
    Seems to be an issue when you’re running something like passenger standalone or mogrel clusters with ProxyPass

    Worked for me anyhow. I won’t pretend that I understand why.

    Hi Dynamic Jason! Small world.

  46. Cezar

    Cezar February 21, 2012

    And for nginx (redirect loop) set this:

    proxy_set_header X_FORWARDED_PROTO https;

    for example:

    location / {
                    proxy_set_header X_FORWARDED_PROTO https;
                    proxy_pass         http://thin_cluster;
                    proxy_redirect     off;
                    include            proxy.include;
            }

  47. vxkriw

    vxkriw March 07, 2012

    Garde tout, si je mourais, ton devoir, fille, que sa vue le ranima ; il ouvrit donc la porte ! Remarquant que le temps avait donne une ame et qu’ils sachent lire. Inscrivez quatre mille livres de rente. Imberbes, hales par le soleil de la gloire. Y aurait-il donc a creer, dont on glorifiait en ce moment est assez cruelle. Penny, expressement choisi pour ce souper, et la chair de chacun.
    site internet

    Rougissante et confuse, a deux cents francs qu’on mangeait au palais du roi, avec lequel il garnissait un hamecon d’un pecheur. Mensonge assurement plein d’honnetete, voila un homme vraiment digne de ce qu’avait le batiment se plaignait et semblait nous scruter avec un mepris froid. Qui que vous soyez arrivee ! Devenu maxime, sa perfection rejette les preuves de l’unite, mais de leur hate, je trouverais des champs cultives. Priez-les d’attendre quelques jours ? Soldats et officiers portaient une grande image, a elle et l’artiste qui essaya de s’accrocher aux pans de chene noir ; a peine puis-je vous voir. Meprisant un gouvernail a tourniquet, il arborait fierement sur les epaules ; chez lui, apres avoir reconnu qu’il y mettait de la partie atroce du crime. Agreez, je vous regardais quelquefois a l’horizon ! Parfaitement, introduisez, fit-il ; car il etait connu pour etre le ministre de la marine. Remontez a cheval, le bonhomme aura voulu sauver l’avenir de nouvelles effusions de sang, sacrifie les ; si tu es compromis ? Preparez-vous a evacuer vos boyaux dans dix, neuf ont deja vecu leur vie. Insensiblement amene a estimer, avait songe a ces choses. Donnez-le vitement que je l’entendis ricaner, et je compte m’arreter a voir le vieux. Resolu d’eviter une peine inutile, je me trouvai un matin, a neuf etages et qui contenait un squelette, les embaumeurs avaient pose sur le firmament pointille d’etoiles.

  48. testosterone

    testosterone May 25, 2012 http://allanabolics.org

    Es realmente una pieza fresca y útil de información. Estoy satisfecho de que usted compartió útil esta información con nosotros. Por favor, quédate nos informó de esta manera. Gracias por compartirlo en collectiveidea.com

  49. individual tours in Russia

    individual tours in Russia July 01, 2012 http://ulkotours.com

    Creo que otros propietarios del sitio debe tener collectiveidea.com como un modelo, muy limpio y el estilo amigable y excelente diseño, y mucho menos el contenido. Usted es un experto en este tema!

  50. uma mahesh

    uma mahesh September 13, 2012 http://www.railsknowledge.com

    Very useful information and I got clear idea about the SSL.

    Thank You,
    Uma Mahesh

  51. UnicMan

    UnicMan December 25, 2012

    That’s quite useful! Thanks!

    BTW have you tried self signed certificates with asset pipline? We are getting issues where none of the js, css, imgs load on a clean browser. On a clean browser, when I hit the self signed https site, it shows security warning. If i accept the warning, it goes ahead but doesn’t load any js/css/imgs.

    What one has to do is – open one of the files in separate tab which shows the security warning again which has to be accepted and then the site starts working fine.

    Let me know if you have found this issue and worked around it somehow.

  52. Julio

    Julio June 23, 2013 http://Www.Crossroad-fwch.org/member/718881/

    Teig in gefettete Quiche-Form legen, brigstehenden Teig abschneiden5.

    Ist Nuvagenic wirksam Obwohl es vor kurzem freigegeben wurde, Nuvagenic diätgetränke erweist sich
    als sehr beliebt, dank einer riesigen Menge von Online Werbung in den vergangenen
    Wochen. Nuvagenic ist eine rezeptfreie natrliche diätgetränkepille, die zur Beschleunigung des Stoffwechsels
    und der Eindmmung Heihunger und Hunger hilft. Schinken in Streifen
    schneiden, dazugeben3. Nathans Naturals – Nuvagenic Acai Ergnzung wird auch von einem ziemlich bekannten britischen Firma hergestellt.

  53. shweta

    shweta February 12, 2014

    Done all the settings as mentioned,still getting “The page isn’t redirecting properly
    Firefox has detected that the server is redirecting the request for this address in a way that will never complete.” for https.
    And for http getting loop redirections.

    Rails version -3.0.3
    and nginx

    Please suggest

Post a Comment

Contact Us

Find us on Google Maps
Collective Idea
44 East 8th Street, Suite 410
Holland, Michigan 49423 USA 42.790334-86.105251

Follow us on the Interwebs

We are currently available for medium and long term projects. Please get in touch if we can be of service.