rack_csrf 2.3.0 → 2.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Changelog.md +13 -0
- data/Gemfile +12 -0
- data/LICENSE.rdoc +1 -1
- data/README.rdoc +61 -1
- data/Rakefile +11 -7
- data/VERSION +1 -1
- data/examples/cuba/Gemfile +1 -1
- data/examples/innate/Gemfile +1 -1
- data/examples/rack/Gemfile +1 -1
- data/examples/sinatra/Gemfile +1 -1
- data/features/check_only_some_specific_requests.feature +22 -0
- data/features/custom_http_methods.feature +46 -0
- data/features/empty_responses.feature +47 -0
- data/features/inspecting_also_get_requests.feature +14 -0
- data/features/raising_exception.feature +27 -0
- data/features/skip_if_block_passes.feature +40 -0
- data/features/skip_some_routes.feature +3 -3
- data/features/step_definitions/request_steps.rb +39 -7
- data/features/step_definitions/setup_steps.rb +56 -14
- data/features/variation_on_header_name.feature +35 -0
- data/lib/rack/csrf.rb +40 -13
- data/rack_csrf.gemspec +16 -7
- data/spec/csrf_spec.rb +105 -59
- metadata +57 -24
data/Changelog.md
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
# v2.4.0 (2012-02-28)
|
2
|
+
|
3
|
+
* Updated examples' Gemfiles.
|
4
|
+
* Dependency management is entrusted totally to Bundler.
|
5
|
+
* Added support for CSRF validation via request headers (courtesy of
|
6
|
+
[jeffreyiacono](https://github.com/jeffreyiacono)).
|
7
|
+
* Improved a bit documentation and testing code.
|
8
|
+
* New option :skip_if (courtesy of
|
9
|
+
[jakubpawlowicz](https://github.com/jakubpawlowicz) and
|
10
|
+
[GoalSmashers](https://github.com/GoalSmashers)).
|
11
|
+
|
12
|
+
|
13
|
+
|
1
14
|
# v2.3.0 (2011-10-23)
|
2
15
|
|
3
16
|
* Updated examples' Gemfiles.
|
data/Gemfile
ADDED
data/LICENSE.rdoc
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
(The MIT License)
|
4
4
|
|
5
|
-
Copyright (c) 2009, 2010, 2011 Emanuele Vicentini
|
5
|
+
Copyright (c) 2009, 2010, 2011, 2012 Emanuele Vicentini
|
6
6
|
|
7
7
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8
8
|
of this software and associated documentation files (the 'Software'), to deal
|
data/README.rdoc
CHANGED
@@ -18,6 +18,8 @@ session. If there's a token and it matches with the stored one, then the
|
|
18
18
|
request is handed over to the next rack component; if not, Rack::Csrf
|
19
19
|
immediately replies with an empty response.
|
20
20
|
|
21
|
+
The anti-forging token can be passed as a request parameter or a header.
|
22
|
+
|
21
23
|
I have not tested Rack::Csrf with Rack 0.4.0 or earlier versions, but it could
|
22
24
|
possibly work.
|
23
25
|
|
@@ -62,6 +64,23 @@ The following options allow you to tweak Rack::Csrf.
|
|
62
64
|
|
63
65
|
Default value: empty.
|
64
66
|
|
67
|
+
[<tt>:skip_if</tt>]
|
68
|
+
Sets a lambda/Proc executed on every request to determine if that request
|
69
|
+
should be let pass untouched:
|
70
|
+
|
71
|
+
use Rack::Csrf, :skip_if => lambda { |request|
|
72
|
+
request.env.key?('HTTP_X_VERY_SPECIAL_HEADER')
|
73
|
+
}
|
74
|
+
|
75
|
+
Your code will receive a request object (see Rack's documentation for
|
76
|
+
details); if it returns anything but nil or false, no further checking is
|
77
|
+
performed and the request is let pass.
|
78
|
+
|
79
|
+
This option is useful if a guarded resource can be accessed by clients who
|
80
|
+
support CSRF token (e.g. browsers) and by ones who don't (e.g. API clients).
|
81
|
+
|
82
|
+
Default value: empty.
|
83
|
+
|
65
84
|
[<tt>:field</tt>]
|
66
85
|
Default field name (see below) is <tt>_csrf</tt>; you can adapt it to
|
67
86
|
specific needs.
|
@@ -78,6 +97,34 @@ The following options allow you to tweak Rack::Csrf.
|
|
78
97
|
|
79
98
|
Default value: csrf.token
|
80
99
|
|
100
|
+
[<tt>:header</tt>]
|
101
|
+
Default header name (see below) is <tt>X_CSRF_TOKEN</tt>; you can adapt it
|
102
|
+
to specific needs.
|
103
|
+
|
104
|
+
use Rack::Csrf, :header => 'MY_CSRF_TOKEN_HEADER'
|
105
|
+
|
106
|
+
This is useful if we want to configure our application to send the CSRF
|
107
|
+
token in all of our AJAX requests via a header. We could implement something
|
108
|
+
along the lines of the following:
|
109
|
+
|
110
|
+
(function(jQuery) {
|
111
|
+
/*
|
112
|
+
* Set the CSRF token for each AJAX request, Rack::Csrf handle the rest.
|
113
|
+
* Assumes your layout has a metatag with name of "_csrf" and you're
|
114
|
+
* using the default Rack:Csrf header setup.
|
115
|
+
*/
|
116
|
+
jQuery.ajaxSetup({
|
117
|
+
beforeSend: function(xhr) {
|
118
|
+
var token = jQuery('meta[name="_csrf"]').attr('content');
|
119
|
+
xhr.setRequestHeader('X_CSRF_TOKEN', token);
|
120
|
+
}
|
121
|
+
});
|
122
|
+
}(jQuery));
|
123
|
+
|
124
|
+
Default value: X_CSRF_TOKEN
|
125
|
+
|
126
|
+
Note that Rack will append "HTTP_" to this value.
|
127
|
+
|
81
128
|
[<tt>:check_also</tt>]
|
82
129
|
By passing an array of uppercase strings to this option you can add them to
|
83
130
|
the list of HTTP methods which "mark" requests that must be searched for the
|
@@ -110,6 +157,9 @@ token.
|
|
110
157
|
[<tt>Rack::Csrf.field</tt> (also <tt>Rack::Csrf.csrf_field</tt>)]
|
111
158
|
Returns the name of the field that must be present in the request.
|
112
159
|
|
160
|
+
[<tt>Rack::Csrf.header</tt> (also <tt>Rack::Csrf.csrf_header</tt>)]
|
161
|
+
Returns the name of the header that must be present in the request.
|
162
|
+
|
113
163
|
[<tt>Rack::Csrf.token(env)</tt> (also <tt>Rack::Csrf.csrf_token(env)</tt>)]
|
114
164
|
Given the request's environment, it generates a random token, stuffs it in
|
115
165
|
the session and returns it to the caller or simply retrieves the already
|
@@ -120,6 +170,16 @@ token.
|
|
120
170
|
insert the token in a standard form like an hidden input field with the
|
121
171
|
right value already entered for you.
|
122
172
|
|
173
|
+
[<tt>Rack::Csrf.metatag(env, options = {})</tt> (also <tt>Rack::Csrf.csrf_metatag(env, options = {})</tt>)]
|
174
|
+
Given the request's environment, it generates a small HTML fragment to
|
175
|
+
insert the token in a standard metatag within your layout's head with the
|
176
|
+
right value already entered for you.
|
177
|
+
|
178
|
+
<tt>options</tt> is an optional hash that can currently take a +name+
|
179
|
+
setting, which will alter the metatag's name attribute.
|
180
|
+
|
181
|
+
Default name: _csrf
|
182
|
+
|
123
183
|
== Working examples
|
124
184
|
|
125
185
|
In the +examples+ directory there are some small, working web applications
|
@@ -148,5 +208,5 @@ forgo responsibilities for keeping your application as safe as possible.
|
|
148
208
|
|
149
209
|
== Copyright
|
150
210
|
|
151
|
-
Copyright (c) 2009, 2010, 2011 Emanuele Vicentini. See LICENSE.rdoc for
|
211
|
+
Copyright (c) 2009, 2010, 2011, 2012 Emanuele Vicentini. See LICENSE.rdoc for
|
152
212
|
details.
|
data/Rakefile
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
|
1
11
|
require 'rake/clean'
|
2
12
|
require 'cucumber/rake/task'
|
3
13
|
require 'rspec/core/rake_task'
|
@@ -5,11 +15,9 @@ require 'rdoc/task'
|
|
5
15
|
require 'jeweler'
|
6
16
|
|
7
17
|
Cucumber::Rake::Task.new :features
|
8
|
-
task :features => :check_dependencies
|
9
18
|
task :default => :features
|
10
19
|
|
11
20
|
RSpec::Core::RakeTask.new :spec
|
12
|
-
task :spec => :check_dependencies
|
13
21
|
task :default => :spec
|
14
22
|
|
15
23
|
version = File.exists?('VERSION') ? File.read('VERSION').strip : ''
|
@@ -31,11 +39,7 @@ Jeweler::Tasks.new do |gem|
|
|
31
39
|
gem.email = 'emanuele.vicentini@gmail.com'
|
32
40
|
gem.homepage = 'https://github.com/baldowl/rack_csrf'
|
33
41
|
gem.rubyforge_project = 'rackcsrf'
|
34
|
-
|
35
|
-
gem.add_development_dependency 'cucumber', '>= 0.1.13'
|
36
|
-
gem.add_development_dependency 'rack-test'
|
37
|
-
gem.add_development_dependency 'rspec', '>= 2.0.0'
|
38
|
-
gem.add_development_dependency 'rdoc', '>= 2.4.2'
|
42
|
+
# dependencies defined in Gemfile
|
39
43
|
gem.rdoc_options << '--line-numbers' << '--inline-source' << '--title' <<
|
40
44
|
"Rack::Csrf #{version}" << '--main' << 'README.rdoc'
|
41
45
|
gem.test_files.clear
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.4.0
|
data/examples/cuba/Gemfile
CHANGED
data/examples/innate/Gemfile
CHANGED
data/examples/rack/Gemfile
CHANGED
data/examples/sinatra/Gemfile
CHANGED
@@ -9,6 +9,10 @@ Feature: Check only some specific requests
|
|
9
9
|
When it receives a POST request for /check/this without the CSRF token
|
10
10
|
Then it responds with 403
|
11
11
|
|
12
|
+
Scenario: Blocking that specific request
|
13
|
+
When it receives a POST request for /check/this without the CSRF header
|
14
|
+
Then it responds with 403
|
15
|
+
|
12
16
|
Scenario Outline: Not blocking other requests
|
13
17
|
When it receives a <method> request for <path> without the CSRF token
|
14
18
|
Then it lets it pass untouched
|
@@ -26,3 +30,21 @@ Feature: Check only some specific requests
|
|
26
30
|
| PATCH | /another/one |
|
27
31
|
| DELETE | /another/one |
|
28
32
|
| CUSTOM | /another/one |
|
33
|
+
|
34
|
+
Scenario Outline: Not blocking other requests
|
35
|
+
When it receives a <method> request for <path> without the CSRF header
|
36
|
+
Then it lets it pass untouched
|
37
|
+
|
38
|
+
Examples:
|
39
|
+
| method | path |
|
40
|
+
| GET | /check/this |
|
41
|
+
| PUT | /check/this |
|
42
|
+
| PATCH | /check/this |
|
43
|
+
| DELETE | /check/this |
|
44
|
+
| CUSTOM | /check/this |
|
45
|
+
| GET | /another/one |
|
46
|
+
| POST | /another/one |
|
47
|
+
| PUT | /another/one |
|
48
|
+
| PATCH | /another/one |
|
49
|
+
| DELETE | /another/one |
|
50
|
+
| CUSTOM | /another/one |
|
@@ -18,6 +18,19 @@ Feature: Handling custom HTTP methods
|
|
18
18
|
| DELETE |
|
19
19
|
| PATCH |
|
20
20
|
|
21
|
+
Scenario Outline: Blocking "standard" requests without the header
|
22
|
+
When it receives a <method> request without the CSRF header
|
23
|
+
Then it responds with 403
|
24
|
+
And the response body is empty
|
25
|
+
|
26
|
+
Examples:
|
27
|
+
| method |
|
28
|
+
| POST |
|
29
|
+
| PUT |
|
30
|
+
| DELETE |
|
31
|
+
| PATCH |
|
32
|
+
|
33
|
+
|
21
34
|
Scenario Outline: Blocking "standard" requests with the wrong token
|
22
35
|
When it receives a <method> request with the wrong CSRF token
|
23
36
|
Then it responds with 403
|
@@ -30,6 +43,18 @@ Feature: Handling custom HTTP methods
|
|
30
43
|
| DELETE |
|
31
44
|
| PATCH |
|
32
45
|
|
46
|
+
Scenario Outline: Blocking "standard" requests with the wrong header
|
47
|
+
When it receives a <method> request with the wrong CSRF header
|
48
|
+
Then it responds with 403
|
49
|
+
And the response body is empty
|
50
|
+
|
51
|
+
Examples:
|
52
|
+
| method |
|
53
|
+
| POST |
|
54
|
+
| PUT |
|
55
|
+
| DELETE |
|
56
|
+
| PATCH |
|
57
|
+
|
33
58
|
Scenario Outline: Blocking requests without the token
|
34
59
|
When it receives a <method> request without the CSRF token
|
35
60
|
Then it responds with 403
|
@@ -40,6 +65,16 @@ Feature: Handling custom HTTP methods
|
|
40
65
|
| ME |
|
41
66
|
| YOU |
|
42
67
|
|
68
|
+
Scenario Outline: Blocking requests without the header
|
69
|
+
When it receives a <method> request without the CSRF header
|
70
|
+
Then it responds with 403
|
71
|
+
And the response body is empty
|
72
|
+
|
73
|
+
Examples:
|
74
|
+
| method |
|
75
|
+
| ME |
|
76
|
+
| YOU |
|
77
|
+
|
43
78
|
Scenario Outline: Blocking requests with the wrong token
|
44
79
|
When it receives a <method> request with the wrong CSRF token
|
45
80
|
Then it responds with 403
|
@@ -50,6 +85,17 @@ Feature: Handling custom HTTP methods
|
|
50
85
|
| ME |
|
51
86
|
| YOU |
|
52
87
|
|
88
|
+
Scenario Outline: Blocking requests with the wrong header
|
89
|
+
When it receives a <method> request with the wrong CSRF header
|
90
|
+
Then it responds with 403
|
91
|
+
And the response body is empty
|
92
|
+
|
93
|
+
Examples:
|
94
|
+
| method |
|
95
|
+
| ME |
|
96
|
+
| YOU |
|
97
|
+
|
98
|
+
|
53
99
|
Scenario Outline: Letting pass "unknown" and safe requests without the token
|
54
100
|
When it receives a <method> request without the CSRF token
|
55
101
|
Then it lets it pass untouched
|
@@ -7,14 +7,26 @@ Feature: Handling of the HTTP requests returning an empty response
|
|
7
7
|
When it receives a GET request with the right CSRF token
|
8
8
|
Then it lets it pass untouched
|
9
9
|
|
10
|
+
Scenario: GET request with the right CSRF header
|
11
|
+
When it receives a GET request with the right CSRF header
|
12
|
+
Then it lets it pass untouched
|
13
|
+
|
10
14
|
Scenario: GET request with the wrong CSRF token
|
11
15
|
When it receives a GET request with the wrong CSRF token
|
12
16
|
Then it lets it pass untouched
|
13
17
|
|
18
|
+
Scenario: GET request with the wrong CSRF header
|
19
|
+
When it receives a GET request with the wrong CSRF header
|
20
|
+
Then it lets it pass untouched
|
21
|
+
|
14
22
|
Scenario: GET request without CSRF token
|
15
23
|
When it receives a GET request without the CSRF token
|
16
24
|
Then it lets it pass untouched
|
17
25
|
|
26
|
+
Scenario: GET request without CSRF header
|
27
|
+
When it receives a GET request without the CSRF header
|
28
|
+
Then it lets it pass untouched
|
29
|
+
|
18
30
|
Scenario Outline: Handling request without CSRF token
|
19
31
|
When it receives a <method> request without the CSRF token
|
20
32
|
Then it responds with 403
|
@@ -27,6 +39,18 @@ Feature: Handling of the HTTP requests returning an empty response
|
|
27
39
|
| DELETE |
|
28
40
|
| PATCH |
|
29
41
|
|
42
|
+
Scenario Outline: Handling request without CSRF header
|
43
|
+
When it receives a <method> request without the CSRF header
|
44
|
+
Then it responds with 403
|
45
|
+
And the response body is empty
|
46
|
+
|
47
|
+
Examples:
|
48
|
+
| method |
|
49
|
+
| POST |
|
50
|
+
| PUT |
|
51
|
+
| DELETE |
|
52
|
+
| PATCH |
|
53
|
+
|
30
54
|
Scenario Outline: Handling request with the right CSRF token
|
31
55
|
When it receives a <method> request with the right CSRF token
|
32
56
|
Then it lets it pass untouched
|
@@ -38,6 +62,17 @@ Feature: Handling of the HTTP requests returning an empty response
|
|
38
62
|
| DELETE |
|
39
63
|
| PATCH |
|
40
64
|
|
65
|
+
Scenario Outline: Handling request with the right CSRF header
|
66
|
+
When it receives a <method> request with the right CSRF header
|
67
|
+
Then it lets it pass untouched
|
68
|
+
|
69
|
+
Examples:
|
70
|
+
| method |
|
71
|
+
| POST |
|
72
|
+
| PUT |
|
73
|
+
| DELETE |
|
74
|
+
| PATCH |
|
75
|
+
|
41
76
|
Scenario Outline: Handling request with the wrong CSRF token
|
42
77
|
When it receives a <method> request with the wrong CSRF token
|
43
78
|
Then it responds with 403
|
@@ -49,3 +84,15 @@ Feature: Handling of the HTTP requests returning an empty response
|
|
49
84
|
| PUT |
|
50
85
|
| DELETE |
|
51
86
|
| PATCH |
|
87
|
+
|
88
|
+
Scenario Outline: Handling request with the wrong CSRF header
|
89
|
+
When it receives a <method> request with the wrong CSRF token
|
90
|
+
Then it responds with 403
|
91
|
+
And the response body is empty
|
92
|
+
|
93
|
+
Examples:
|
94
|
+
| method |
|
95
|
+
| POST |
|
96
|
+
| PUT |
|
97
|
+
| DELETE |
|
98
|
+
| PATCH |
|
@@ -18,3 +18,17 @@ Feature: Inspecting also GET requests
|
|
18
18
|
When it receives a GET request without the CSRF token
|
19
19
|
Then it responds with 403
|
20
20
|
And the response body is empty
|
21
|
+
|
22
|
+
Scenario: GET request with the right CSRF header
|
23
|
+
When it receives a GET request with the right CSRF header
|
24
|
+
Then it lets it pass untouched
|
25
|
+
|
26
|
+
Scenario: GET request with the wrong CSRF header
|
27
|
+
When it receives a GET request with the wrong CSRF header
|
28
|
+
Then it responds with 403
|
29
|
+
And the response body is empty
|
30
|
+
|
31
|
+
Scenario: GET request without the CSRF header
|
32
|
+
When it receives a GET request without the CSRF header
|
33
|
+
Then it responds with 403
|
34
|
+
And the response body is empty
|
@@ -7,6 +7,10 @@ Feature: Handling of the HTTP requests raising an exception
|
|
7
7
|
When it receives a GET request without the CSRF token
|
8
8
|
Then it lets it pass untouched
|
9
9
|
|
10
|
+
Scenario: GET request without CSRF header
|
11
|
+
When it receives a GET request without the CSRF header
|
12
|
+
Then it lets it pass untouched
|
13
|
+
|
10
14
|
Scenario Outline: Handling request without CSRF token
|
11
15
|
When it receives a <method> request without the CSRF token
|
12
16
|
Then there is no response
|
@@ -30,6 +34,17 @@ Feature: Handling of the HTTP requests raising an exception
|
|
30
34
|
| DELETE |
|
31
35
|
| PATCH |
|
32
36
|
|
37
|
+
Scenario Outline: Handling request with the right CSRF header
|
38
|
+
When it receives a <method> request with the right CSRF header
|
39
|
+
Then it lets it pass untouched
|
40
|
+
|
41
|
+
Examples:
|
42
|
+
| method |
|
43
|
+
| POST |
|
44
|
+
| PUT |
|
45
|
+
| DELETE |
|
46
|
+
| PATCH |
|
47
|
+
|
33
48
|
Scenario Outline: Handling request with the wrong CSRF token
|
34
49
|
When it receives a <method> request with the wrong CSRF token
|
35
50
|
Then there is no response
|
@@ -41,3 +56,15 @@ Feature: Handling of the HTTP requests raising an exception
|
|
41
56
|
| PUT |
|
42
57
|
| DELETE |
|
43
58
|
| PATCH |
|
59
|
+
|
60
|
+
Scenario Outline: Handling request with the wrong CSRF header
|
61
|
+
When it receives a <method> request with the wrong CSRF header
|
62
|
+
Then there is no response
|
63
|
+
And an exception is climbing up the stack
|
64
|
+
|
65
|
+
Examples:
|
66
|
+
| method |
|
67
|
+
| POST |
|
68
|
+
| PUT |
|
69
|
+
| DELETE |
|
70
|
+
| PATCH |
|