This is just a small Rack middleware whose only goal is to lessen the hazards posed by CSRF attacks by trying to ensure that all requests of particular types come from the right client, not from a mischievous impersonator.
Rack::Csrf is not tailored to any particular web framework, so it can be used with your preferred Rack-based framework.
First of all, beyond Rack itself, there is only one prerequisite: you must set up your rack with a session middleware, inserted anywhere before Rack::Csrf.
Every POST, PUT, DELETE and PATCH request will be searched for the anti-forging token, randomly generated by Rack::Csrf and stored inside the session. If there’s a token and it matches with the stored one, then the request is handed over to the next rack component; if not, Rack::Csrf immediately replies with an empty response.
I have not tested Rack::Csrf with Rack 0.4.0 or earlier versions, but it could possibly work.
The following options allow you to tweak Rack::Csrf.
:raise
-
Set it to true to change the handling of bad requests: instead of producing an empty response, Rack::Csrf will raise an exception of class Rack::Csrf::InvalidCsrfToken.
use Rack::Csrf, :raise => true
Default value: false.
:check_only
-
By default, Rack::Csrf checks every POST, PUT, DELETE and PATCH request; passing an array of HTTP method/URL (regular expressions allowed) to this option you can change this behavior to only check the items on this list.
use Rack::Csrf, :check_only => ['POST:/checking', 'PUT:/me_too', 'DELETE:/cars/.*\.xml', 'PATCH:/this/.*/too']
Please, note that the regular expressions are not escaped and it is your duty to write them correctly. Empty PATH_INFO (see Rack’s spec for details) is treated as ‘/’ for this check.
Default value: empty.
:skip
-
By default, Rack::Csrf checks every POST, PUT, DELETE and PATCH request; passing an array of HTTP method/URL (regular expressions allowed) to this option you can choose what to let pass unchecked:
use Rack::Csrf, :skip => ['POST:/not_checking', 'PUT:/me_too', 'DELETE:/cars/.*\.xml', 'PATCH:/this/.*/too']
Please, note that the regular expressions are not escaped and it is your duty to write them correctly. Empty PATH_INFO (see Rack’s spec for details) is treated as ‘/’ for this check.
Default value: empty.
:field
-
Default field name (see below) is
_csrf
; you can adapt it to specific needs.use Rack::Csrf, :field => '_my_own_csrf_field'
Default value: _csrf
:key
-
The key used to store/retrieve the token from the Rack session; you can adapt it to specific needs.
use Rack::Csrf, :key => 'my.own_session.key'
Default value: csrf.token
:check_also
-
By passing an array of uppercase strings to this option you can add them to the list of HTTP methods which “mark” requests that must be searched for the anti-forging token.
use Rack::Csrf, :check_also => %w(WHATEVER YOU WANT EVEN GET)
Default value: empty
The :browser_only
option has been removed; you do not need to edit any rackup file because Rack::Csrf simply ignores unknown options. Changes introduced in Rack version 1.1.0 tightened the parsing of POST params, so requests need to have the right Content-Type (or none at all); these Content-Types are exactly those used also by browsers and so there is no use for :browser_only
anymore.
The ill devised :browser_only
option could have been used to “protect” an API, but I think it might be better to use a combination of :skip
and formatted URLs.
The following class methods try to ease the insertion of the anti-forging token.
Rack::Csrf.key
(alsoRack::Csrf.csrf_key
)-
Returns the name of the key used to store/retrieve the token from the Rack session.
Rack::Csrf.field
(alsoRack::Csrf.csrf_field
)-
Returns the name of the field that must be present in the request.
Rack::Csrf.token(env)
(alsoRack::Csrf.csrf_token(env)
)-
Given the request’s environment, it generates a random token, stuffs it in the session and returns it to the caller or simply retrieves the already stored one.
Rack::Csrf.tag(env)
(alsoRack::Csrf.csrf_tag(env)
)-
Given the request’s environment, it generates a small HTML fragment to insert the token in a standard form like an hidden input field with the right value already entered for you.
In the examples
directory there are some small, working web applications written with different Rack-based frameworks. They are named after the used framework; see the various README files for other details.
If you want to help:
-
fork the project on GitHub;
-
work in a topic branch;
-
add features/specs for your additions or bug fixes;
-
write your additions/bug fixes;
-
commit;
-
send me a pull request for the topic branch.
If you have any issue, please post them on the project’s issue list on GitHub.
I cannot stress enough that this middleware is not a bulletproof vest or a panacea for the CSRF plague; it is just an aid and by using it you cannot forgo responsibilities for keeping your application as safe as possible.
Copyright © 2009, 2010, 2011 Emanuele Vicentini. See LICENSE.rdoc for details.