kalenkov/last_line

View on GitHub
README.md

Summary

Maintainability
Test Coverage
[![Code Climate](https://codeclimate.com/github/kalenkov/last_line.png)](https://codeclimate.com/github/kalenkov/last_line)

# 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 of `routes.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