LastLine
Last Line of CSRF Defence
Rails provides CSRF protection for your application out of the box. This protection covers only non-GET (or HEAD) requests, as GET requests are not supposed to change any state. Unfortunately, there are two main gaps in default CSRF prevention:
-
Routing information is handled independently from controller logic. It is not trivial to trace which actions are allowed to process GET requests. Most common example - un-commenting generic route
match ':controller(/:action(/:id))(.:format)'
(hidden at the end ofroutes.rb
) opens all controller actions to GET requests. -
Sometimes it is important to provide CSRF protection for GET requests too. Common use case for this - redirect from external service, like third party authentication.
LastLine is an attempt to bridge these gaps. It provides
-
Whitelisting actions for GET requests on controller level
-
A way to verify authenticity token for GET request
Installation
Include in your Gemfile
gem 'last_line'
and run
bundle install
Usage
Whitelisting GET actions
To require GET request whitelisting for the whole application, insert protect_from_gets
in your
ApplicationController
after protect_from_forgery
:
class ApplicationController < ActionController::Base
protect_from_forgery
protect_from_gets
[...]
end
In case you want to whitelist GETs in a particular controller only, insert the same line in your controller
instead of ApplicationController
(not recommended)
If you want to whitelist GET actions in your application, but exclude some controller from whitelisting (not recommended):
class MySafeController < ApplicationController
allow_gets :all
end
The best (easiest to trace) way to whitelist a particular action is to add allow_get :action
after its definition:
def index
[...]
end
allow_get :index
Alternatively you can whitelist all actions in the same place. For this include in your controller
allow_gets :only => [:action1, :action2]
There is also a simple way to do blacklisting instead of whitelisting (not recommended, as it is much less reliable):
allow_gets :except => [:action1, :action2]
CSRF protection for GET actions
You can protect specific action from CSRF by specifying it as a protected_get
. Such protection will automatically
whitelist corresponding action for GET requests.
def redirected
[...]
end
protected_get :redirected
When this action is called without form_authenticity_token
as explicit parameter or in the header,
handle_unverified_request
will be called (default Rails behavior is to clear session data)
You can add token as a parameter to your get request providing it explicitly
<%= link_to 'Protected get', some_defined_path(request_forgery_protection_token => form_authenticity_token) %>
Please be aware that protected_get
adds its filter on top of filter chain to avoid potential side effects
of other filters. It means that none of subsequent filters that rely on session data will work if request is
not verified