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.
@@ -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
@@ -0,0 +1,12 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'rack', '>= 0.9'
4
+
5
+ group :development do
6
+ gem 'bundler', '>= 1.0.0'
7
+ gem 'cucumber', '>= 1.1.1'
8
+ gem 'rack-test'
9
+ gem 'rspec', '>= 2.0.0'
10
+ gem 'rdoc', '>= 2.4.2'
11
+ gem 'jeweler'
12
+ end
@@ -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
@@ -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
- gem.add_dependency 'rack', '>= 0.9'
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.3.0
1
+ 2.4.0
@@ -1,3 +1,3 @@
1
1
  source 'http://rubygems.org'
2
2
 
3
- gem 'cuba', '2.1.0'
3
+ gem 'cuba', '>= 2.1.0', '<= 2.2.1'
@@ -1,3 +1,3 @@
1
1
  source 'http://rubygems.org'
2
2
 
3
- gem 'innate', '>= 2009.07', '<= 2011.04'
3
+ gem 'innate', '>= 2009.07', '<= 2011.12'
@@ -1,3 +1,3 @@
1
1
  source 'http://rubygems.org'
2
2
 
3
- gem 'rack', '>= 1.0.0', '<= 1.3.5'
3
+ gem 'rack', '>= 1.0.0', '<= 1.4.1'
@@ -1,3 +1,3 @@
1
1
  source 'http://rubygems.org'
2
2
 
3
- gem 'sinatra', '>= 0.9.4', '<= 1.3.1'
3
+ gem 'sinatra', '>= 0.9.4', '<= 1.3.2'
@@ -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 |