rack_csrf 2.3.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 |
|