Permalink
Browse files

Merge pull request #4 from jeffreyiacono/master

add csrf token validation in via request header, add metatag helper
  • Loading branch information...
2 parents 87f438e + cb56963 commit e73d62df6e90f0a144b082ba175409c6714e001a @baldowl committed Feb 18, 2012
View
@@ -0,0 +1,2 @@
+Gemfile.lock
+.rvmrc
View
@@ -0,0 +1,8 @@
+source 'http://rubygems.org'
+
+gem 'rack'
+gem 'rack-test'
+gem 'rspec'
+gem 'cucumber'
+gem 'rdoc'
+gem 'jeweler'
View
@@ -18,6 +18,8 @@ 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.
+The anti-forging token can be passed as a request parameter or a header.
+
I have not tested Rack::Csrf with Rack 0.4.0 or earlier versions, but it could
possibly work.
@@ -95,6 +97,35 @@ The following options allow you to tweak Rack::Csrf.
Default value: csrf.token
+[<tt>:header</tt>]
+ Default header name (see below) is <tt>X_CSRF_TOKEN</tt>; you can adapt it to
+ specific needs.
+
+ use Rack::Csrf, :header => 'MY_CSRF_TOKEN_HEADER'
+
+ This is useful if we want to configure our application to send the csrf
+ token in all of our ajax requests via a header. We could implement something
+ along the lines of the following:
+
+ (function(jQuery) {
+ /**
+ * Set the csrf token for each ajax operation,
+ * rack / rack_csrf handle the rest.
+ * Assumes your layout has a metatag with name of "_csrf" and you're using
+ * the default Rack:Csrf header setup.
+ */
+ jQuery.ajaxSetup({
+ beforeSend: function(xhr) {
+ var token = jQuery('meta[name="_csrf"]').attr('content');
+ xhr.setRequestHeader('X_CSRF_TOKEN', token);
+ }
+ });
+ }(jQuery));
+
+ Default value: X_CSRF_TOKEN
+
+ Note that Rack will append "HTTP_" to this value.
+
[<tt>:check_also</tt>]
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
@@ -127,6 +158,9 @@ token.
[<tt>Rack::Csrf.field</tt> (also <tt>Rack::Csrf.csrf_field</tt>)]
Returns the name of the field that must be present in the request.
+[<tt>Rack::Csrf.header</tt> (also <tt>Rack::Csrf.csrf_header</tt>)]
+ Returns the name of the header that must be present in the request.
+
[<tt>Rack::Csrf.token(env)</tt> (also <tt>Rack::Csrf.csrf_token(env)</tt>)]
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
@@ -137,6 +171,16 @@ token.
insert the token in a standard form like an hidden input field with the
right value already entered for you.
+[<tt>Rack::Csrf.metatag(env, options = {})</tt> (also <tt>Rack::Csrf.csrf_metatag(env, options = {})</tt>)]
+ Given the request's environment, it generates a small HTML fragment to
+ insert the token in a standard metatag within your layout's head with the
+ right value already entered for you.
+
+ <tt>options</tt> is an optional hash that can currently take a +name+ setting, which
+ will alter the metatag's name attribute.
+
+ Default name: _csrf
+
== Working examples
In the +examples+ directory there are some small, working web applications
@@ -9,6 +9,10 @@ Feature: Check only some specific requests
When it receives a POST request for /check/this without the CSRF token
Then it responds with 403
+ Scenario: Blocking that specific request
+ When it receives a POST request for /check/this without the CSRF header
+ Then it responds with 403
+
Scenario Outline: Not blocking other requests
When it receives a <method> request for <path> without the CSRF token
Then it lets it pass untouched
@@ -26,3 +30,21 @@ Feature: Check only some specific requests
| PATCH | /another/one |
| DELETE | /another/one |
| CUSTOM | /another/one |
+
+ Scenario Outline: Not blocking other requests
+ When it receives a <method> request for <path> without the CSRF header
+ Then it lets it pass untouched
+
+ Examples:
+ | method | path |
+ | GET | /check/this |
+ | PUT | /check/this |
+ | PATCH | /check/this |
+ | DELETE | /check/this |
+ | CUSTOM | /check/this |
+ | GET | /another/one |
+ | POST | /another/one |
+ | PUT | /another/one |
+ | PATCH | /another/one |
+ | DELETE | /another/one |
+ | CUSTOM | /another/one |
@@ -18,6 +18,19 @@ Feature: Handling custom HTTP methods
| DELETE |
| PATCH |
+ Scenario Outline: Blocking "standard" requests without the header
+ When it receives a <method> request without the CSRF header
+ Then it responds with 403
+ And the response body is empty
+
+ Examples:
+ | method |
+ | POST |
+ | PUT |
+ | DELETE |
+ | PATCH |
+
+
Scenario Outline: Blocking "standard" requests with the wrong token
When it receives a <method> request with the wrong CSRF token
Then it responds with 403
@@ -30,6 +43,18 @@ Feature: Handling custom HTTP methods
| DELETE |
| PATCH |
+ Scenario Outline: Blocking "standard" requests with the wrong header
+ When it receives a <method> request with the wrong CSRF header
+ Then it responds with 403
+ And the response body is empty
+
+ Examples:
+ | method |
+ | POST |
+ | PUT |
+ | DELETE |
+ | PATCH |
+
Scenario Outline: Blocking requests without the token
When it receives a <method> request without the CSRF token
Then it responds with 403
@@ -40,6 +65,16 @@ Feature: Handling custom HTTP methods
| ME |
| YOU |
+ Scenario Outline: Blocking requests without the header
+ When it receives a <method> request without the CSRF header
+ Then it responds with 403
+ And the response body is empty
+
+ Examples:
+ | method |
+ | ME |
+ | YOU |
+
Scenario Outline: Blocking requests with the wrong token
When it receives a <method> request with the wrong CSRF token
Then it responds with 403
@@ -50,6 +85,17 @@ Feature: Handling custom HTTP methods
| ME |
| YOU |
+ Scenario Outline: Blocking requests with the wrong header
+ When it receives a <method> request with the wrong CSRF header
+ Then it responds with 403
+ And the response body is empty
+
+ Examples:
+ | method |
+ | ME |
+ | YOU |
+
+
Scenario Outline: Letting pass "unknown" and safe requests without the token
When it receives a <method> request without the CSRF token
Then it lets it pass untouched
@@ -7,14 +7,26 @@ Feature: Handling of the HTTP requests returning an empty response
When it receives a GET request with the right CSRF token
Then it lets it pass untouched
+ Scenario: GET request with the right CSRF header
+ When it receives a GET request with the right CSRF header
+ Then it lets it pass untouched
+
Scenario: GET request with the wrong CSRF token
When it receives a GET request with the wrong CSRF token
Then it lets it pass untouched
+ Scenario: GET request with the wrong CSRF header
+ When it receives a GET request with the wrong CSRF header
+ Then it lets it pass untouched
+
Scenario: GET request without CSRF token
When it receives a GET request without the CSRF token
Then it lets it pass untouched
+ Scenario: GET request without CSRF header
+ When it receives a GET request without the CSRF header
+ Then it lets it pass untouched
+
Scenario Outline: Handling request without CSRF token
When it receives a <method> request without the CSRF token
Then it responds with 403
@@ -27,6 +39,18 @@ Feature: Handling of the HTTP requests returning an empty response
| DELETE |
| PATCH |
+ Scenario Outline: Handling request without CSRF header
+ When it receives a <method> request without the CSRF header
+ Then it responds with 403
+ And the response body is empty
+
+ Examples:
+ | method |
+ | POST |
+ | PUT |
+ | DELETE |
+ | PATCH |
+
Scenario Outline: Handling request with the right CSRF token
When it receives a <method> request with the right CSRF token
Then it lets it pass untouched
@@ -38,6 +62,17 @@ Feature: Handling of the HTTP requests returning an empty response
| DELETE |
| PATCH |
+ Scenario Outline: Handling request with the right CSRF header
+ When it receives a <method> request with the right CSRF header
+ Then it lets it pass untouched
+
+ Examples:
+ | method |
+ | POST |
+ | PUT |
+ | DELETE |
+ | PATCH |
+
Scenario Outline: Handling request with the wrong CSRF token
When it receives a <method> request with the wrong CSRF token
Then it responds with 403
@@ -49,3 +84,15 @@ Feature: Handling of the HTTP requests returning an empty response
| PUT |
| DELETE |
| PATCH |
+
+ Scenario Outline: Handling request with the wrong CSRF header
+ When it receives a <method> request with the wrong CSRF token
+ Then it responds with 403
+ And the response body is empty
+
+ Examples:
+ | method |
+ | POST |
+ | PUT |
+ | DELETE |
+ | PATCH |
@@ -18,3 +18,17 @@ Feature: Inspecting also GET requests
When it receives a GET request without the CSRF token
Then it responds with 403
And the response body is empty
+
+ Scenario: GET request with the right CSRF header
+ When it receives a GET request with the right CSRF header
+ Then it lets it pass untouched
+
+ Scenario: GET request with the wrong CSRF header
+ When it receives a GET request with the wrong CSRF header
+ Then it responds with 403
+ And the response body is empty
+
+ Scenario: GET request without the CSRF header
+ When it receives a GET request without the CSRF header
+ Then it responds with 403
+ And the response body is empty
@@ -7,6 +7,10 @@ Feature: Handling of the HTTP requests raising an exception
When it receives a GET request without the CSRF token
Then it lets it pass untouched
+ Scenario: GET request without CSRF header
+ When it receives a GET request without the CSRF header
+ Then it lets it pass untouched
+
Scenario Outline: Handling request without CSRF token
When it receives a <method> request without the CSRF token
Then there is no response
@@ -30,6 +34,17 @@ Feature: Handling of the HTTP requests raising an exception
| DELETE |
| PATCH |
+ Scenario Outline: Handling request with the right CSRF header
+ When it receives a <method> request with the right CSRF header
+ Then it lets it pass untouched
+
+ Examples:
+ | method |
+ | POST |
+ | PUT |
+ | DELETE |
+ | PATCH |
+
Scenario Outline: Handling request with the wrong CSRF token
When it receives a <method> request with the wrong CSRF token
Then there is no response
@@ -41,3 +56,15 @@ Feature: Handling of the HTTP requests raising an exception
| PUT |
| DELETE |
| PATCH |
+
+ Scenario Outline: Handling request with the wrong CSRF header
+ When it receives a <method> request with the wrong CSRF header
+ Then there is no response
+ And an exception is climbing up the stack
+
+ Examples:
+ | method |
+ | POST |
+ | PUT |
+ | DELETE |
+ | PATCH |
@@ -5,7 +5,7 @@ Feature: Skipping the check if a block passes
| name | value |
| token | skip |
| User-Agent | MSIE |
- When it receives a request with headers <name> = <value> without the CSRF token
+ When it receives a request with headers <name> = <value> without the CSRF token or header
Then it lets it pass untouched
Examples:
@@ -18,7 +18,7 @@ Feature: Skipping the check if a block passes
| name | value |
| token | skip |
| User-Agent | MSIE |
- When it receives a request with headers <name> = <value> without the CSRF token
+ When it receives a request with headers <name> = <value> without the CSRF token or header
Then it responds with 403
Examples:
@@ -31,7 +31,7 @@ Feature: Skipping the check if a block passes
Given a rack with the anti-CSRF middleware and both the :skip and :skip_if options
| name | value | path |
| token | skip | POST:/ |
- When it receives a request with headers <name> = <value>, <method>, and without the CSRF token
+ When it receives a request with headers <name> = <value>, <method>, and without the CSRF token or header
Then it lets it pass untouched
Examples:
@@ -8,7 +8,7 @@ Feature: Skipping the check for some specific routes
| POST:/not_.*\.json |
| DELETE:/cars/.*\.xml |
| PATCH:/this/one/too |
- When it receives a <method> request for <path> without the CSRF token
+ When it receives a <method> request for <path> without the CSRF token or header
Then it lets it pass untouched
Examples:
@@ -28,7 +28,7 @@ Feature: Skipping the check for some specific routes
| POST:/not_.*\.json |
| DELETE:/cars/.*\.xml |
| PATCH:/this/one/too |
- When it receives a <method> request for <path> without the CSRF token
+ When it receives a <method> request for <path> without the CSRF token or header
Then it responds with 403
And the response body is empty
@@ -63,7 +63,7 @@ Feature: Skipping the check for some specific routes
| PUT:/ |
| DELETE:/ |
| PATCH:/ |
- When it receives a <method> request with neither PATH_INFO nor CSRF token
+ When it receives a <method> request with neither PATH_INFO nor CSRF token or header
Then it lets it pass untouched
Examples:
Oops, something went wrong.

0 comments on commit e73d62d

Please sign in to comment.