SSL On Specific Actions In Rails
- February 1, 2016
The reason for this post is we wanted to make some part of our application to be served over https. We’re working on a shopping site so wanted the cart and payment sections to be secure. There were few options available and had to make a choice. Here’s the finding.
The popular ways of requiring SSL in Rails are:
- Passing in
protocol: 'https'
in calls to*_url
helpers when generating links and forms. - Specifying
constraints: { protocol: 'https' }
on specific routes to accomplish the same thing, but in a central place. config.force_ssl = true
- Using ssl_requirement gem.
Option 1
- It will fill your views and helpers with extraneous code and your ERB output with absolute URLs, which will pack more bytes in your pages than relative ones.
- You will have to make sure you’re specifying HTTPS in each URL helper call for that URL, which is not DRY.
- It will do nothing on the controller-side to ensure communication between browser and server actually took place over HTTPS.
Option 2
- It will take care of centralized HTTPS requirements for helpers, but it will make your routes messy because you have to require SSL for an entire resource or break out actions on resources that require SSL into their own route lines.
resources :users, only: [:new, :create], constraints: { protocol: 'https' }
resources :users, only: :show
Option 3
- It can be used when it’s site wide ssl which was not the case for us. So this possibility was ruled out.
Option 4
I liked this option because:
- It ensures SSL actually took place on the controller side.
- It also allows you to more-DRYly define SSL requirements in one-place: the controller because of redirects.
class UsersController < ApplicationController
ssl_required :new, :create
...
end
- A before_filter ensures the proper protocol is used for an action. If the right protocol is used, the action executes as expected. If the wrong protocol is used, Rails tells the browser to try the request again over the proper protocol.
- You can completely ignore specifying HTTPS in helpers to URLs for pages that need to have the security lock icon. When fetched with HTTP, the server will tell the browser to request it again, but this time over HTTPS.
- All of your URLs can be generated by
*_path
helpers instead of*_url
helpers. If the origin page is HTTP, the relative URL will be HTTP. If the origin page is HTTPS, the relative URL will be HTTPS. In either case, ssl_requirement will ensure the right protocol is used. - It gives me easy configuration to enable or disable ssl checks and adds secure option to url helpers and will covert url helpers to use the correct protocol based on ssl enabled/disabled.
# in your environment file
config.after_initialize do
SslRequirement.disable_ssl_check = true
end
# in your views
cart_path(secure: true)
- One can use separate ports and even hosts for http and https
config.after_initialize do
SslRequirement.ssl_port = 3001
SslRequirement.non_ssl_port = 3000
SslRequirement.ssl_host = "secure.yourdomain.com"
SslRequirement.non_ssl_host = "non-secure.yourdomain.com"
end