safe_cookies 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/README.md +46 -51
- data/lib/safe_cookies.rb +5 -3
- data/lib/safe_cookies/configuration.rb +5 -2
- data/lib/safe_cookies/version.rb +1 -1
- data/spec/safe_cookies_spec.rb +55 -45
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
YWE0YmVmNWE0NjE3N2ZiYWUzNDM2ODYwMDFhNGNkYTE1Yzc2ZjllYQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
NDliMDkwMDFjOTMxZDVhNmU4NjgyZDgxZTQ1OWQ1N2E4NjFhNmZmYw==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
YzYxNGU4MmIyNjg1MDhjNzM0ZjRmNWMxZGYwNmM4MDUxYmMwNDE0ZDRiYmQx
|
10
|
+
YmY0NTdiOGUxODQ4NWFiOTUzOTUyMjM0MTU2ZWUyOGQ3OGUxYjZhMDYzZGFk
|
11
|
+
ZDc5NTcwYjg2Zjc5MWM0MzgwMGE3YTA2NGMyZmQxYmIyOTg5NGY=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
NWI3YmNhNzE2ODI1YzQ2ZGQ0NTk3NTAxODg5MTFhMWI0MDIxYWJmODNlZTU2
|
14
|
+
ZjVjZDRkYjE1YmNlNTU4YTIwYTYxNTMyNDFjMWQ2MGFiOTU3ZGNkNTlmZmZi
|
15
|
+
ZTdlOTI1M2ZhNTE1NDQzZTRiNTIzMjc2NTYxYzk3MGQ1Zjk5N2Q=
|
data/README.md
CHANGED
@@ -1,84 +1,79 @@
|
|
1
1
|
# SafeCookies
|
2
2
|
|
3
|
-
This
|
3
|
+
This gem has a middleware that will make all cookies secure. In detail, it will
|
4
|
+
to two separate things:
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
6
|
+
1) set all new application cookies 'HttpOnly', unless specified otherwise;
|
7
|
+
set all new application cookies 'secure', if the request came via HTTPS and not specified otherwise
|
8
|
+
|
9
|
+
2) rewrite request cookies, setting both flags as above
|
8
10
|
|
9
11
|
## Installation
|
10
12
|
|
11
13
|
### Step 1
|
12
|
-
Add
|
13
|
-
|
14
|
-
gem 'safe_cookies'
|
15
|
-
|
16
|
-
Then run `bundle install`.
|
14
|
+
Add `gem 'safe_cookies'` to your application's Gemfile, then run `bundle install`.
|
17
15
|
|
18
|
-
|
19
|
-
Rails
|
16
|
+
### Step 2
|
17
|
+
**Rails 3 and 4**: add the following lines to the application block in config/application.rb:
|
20
18
|
|
19
|
+
require 'safe_cookies'
|
20
|
+
config.middleware.insert_before ActionDispatch::Cookies, SafeCookies::Middleware
|
21
21
|
|
22
|
-
|
23
|
-
**Rails 3 and 4**: add the following line in config/application.rb:
|
22
|
+
**Rails 2:** add the following lines to the initializer block in config/environment.rb:
|
24
23
|
|
25
|
-
|
26
|
-
|
27
|
-
config.middleware.insert_before ActionDispatch::Cookies, SafeCookies::Middleware
|
28
|
-
end
|
24
|
+
require 'safe_cookies'
|
25
|
+
config.middleware.insert_before ActionController::Session::CookieStore, SafeCookies::Middleware
|
29
26
|
|
30
|
-
**Rails 2:** add the following lines in config/environment.rb:
|
31
27
|
|
32
|
-
|
33
|
-
|
34
|
-
require 'safe_cookies'
|
35
|
-
config.middleware.insert_before ActionController::Session::CookieStore, SafeCookies::Middleware
|
36
|
-
end
|
28
|
+
Now all your cookies will be made `secure` and `HttpOnly`. But what if you need
|
29
|
+
a cookie to be accessible via HTTP or Javascript?
|
37
30
|
|
38
|
-
###
|
39
|
-
|
40
|
-
|
31
|
+
### Having a cookie non-secure or non-HttpOnly
|
32
|
+
Tell the middleware which cookies not to make `secure` or `HttpOnly` by
|
33
|
+
registering them. Do it either just after the lines you added above or in an
|
34
|
+
initializer (e.g. in `config/initializers/safe_cookies.rb`). The `:expire_after` option is required.
|
41
35
|
|
42
36
|
SafeCookies.configure do |config|
|
43
|
-
config.register_cookie :remember_token, :expire_after => 1.year
|
44
|
-
config.register_cookie :last_action, :expire_after => 30.days
|
45
37
|
config.register_cookie :default_language, :expire_after => 10.years, :secure => false
|
46
38
|
config.register_cookie :javascript_data, :expire_after => 1.day, :http_only => false
|
47
39
|
end
|
48
40
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
41
|
+
### Employing SafeCookies in apps that are already running in production
|
42
|
+
Unfortunately, [the client won't ever tell us](http://tools.ietf.org/html/rfc6265#section-4.2.2)
|
43
|
+
if it stores the cookie with flags such as `secure` or which expiry date it
|
44
|
+
currently has. Therefore, in order to make the middleware retroactively secure
|
45
|
+
cookies owned by the client, you need to register each of those cookies with
|
46
|
+
the middleware, specifying their properties.
|
47
|
+
|
48
|
+
Carefully scan your app for cookies you are using. There's no easy way to find
|
49
|
+
out if you missed one (but see below for some help the gem provides).
|
54
50
|
|
55
|
-
|
51
|
+
SafeCookies.configure do |config|
|
52
|
+
config.register_cookie :remember_token, :expire_after => 1.year
|
53
|
+
config.register_cookie :last_action, :expire_after => 30.days, :path => '/commerce'
|
54
|
+
end
|
56
55
|
|
57
|
-
|
58
|
-
Override `SafeCookies::Middleware#handle_unknown_cookies(cookies)` to notify you
|
59
|
-
e.g. by email (see "Dealing with unregistered cookies" below).
|
56
|
+
Available options are: `:expire_after` (required)`, :path, :secure, :http_only`.
|
60
57
|
|
61
58
|
|
62
|
-
## Dealing with
|
59
|
+
## Dealing with unknown cookies
|
63
60
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
currently has. Therefore, it is important to register all cookies that may be
|
68
|
-
sent by the client, specifying their properties. Unregistered cookies cannot be
|
69
|
-
secured by the middleware.
|
61
|
+
There are lots of cookies your application receives that you never did set.
|
62
|
+
However, if you want to know about any unknown cookies touching your
|
63
|
+
application, SafeCookies offers two ways to achieve this.
|
70
64
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
the config initializer for customized behaviour (like, notifying you per email).
|
65
|
+
1) If you set `config.log_unknown_cookies = true` in the configuration, all
|
66
|
+
unknown cookies will be written to the Rails log. When you start implementing
|
67
|
+
the middleware, closely watch it to find cookies you forgot to register.
|
75
68
|
|
76
|
-
You
|
69
|
+
2) You may overwrite `SafeCookies::Middleware#handle_unknown_cookies(cookies)`
|
70
|
+
in the config initializer for customized behaviour (like, notifying you per
|
71
|
+
email).
|
77
72
|
|
78
73
|
|
79
74
|
## Ignoring cookies
|
80
75
|
|
81
|
-
|
76
|
+
The middleware won't see request cookies that are configured to be ignored. Use this to keep your logs lean, if you are using the `log_unknown_cookies` option.
|
82
77
|
|
83
78
|
You can tell the middleware to ignore cookies with the `config.ignore_cookie`
|
84
79
|
directive, which takes either a String or a Regex parameter. Be careful when using regular expressions!
|
@@ -93,7 +88,7 @@ Users would get multiple cookies for that domain, leading to issues like being u
|
|
93
88
|
The configuration option `config.fix_paths` turns on fixing this error. It requires an option
|
94
89
|
`:for_cookies_secured_before => Time.parse('some minutes after you will have deployed')` which reflects the
|
95
90
|
point of time from which cookies will be secured with the correct path. The middleware will fix the cookie
|
96
|
-
paths by rewriting all cookies that it has already secured, but only if
|
91
|
+
paths by rewriting all cookies that it has already secured, but only if they were secured before the time
|
97
92
|
you specified.
|
98
93
|
|
99
94
|
|
data/lib/safe_cookies.rb
CHANGED
@@ -64,6 +64,9 @@ module SafeCookies
|
|
64
64
|
unknown_cookie_names = request_cookie_names - known_cookie_names
|
65
65
|
|
66
66
|
if unknown_cookie_names.any?
|
67
|
+
message = "Request for '#{@request.url}' had unknown cookies: #{unknown_cookie_names.join(', ')}"
|
68
|
+
log(message) if @config.log_unknown_cookies
|
69
|
+
|
67
70
|
handle_unknown_cookies(unknown_cookie_names)
|
68
71
|
end
|
69
72
|
end
|
@@ -128,11 +131,10 @@ module SafeCookies
|
|
128
131
|
|
129
132
|
# API method
|
130
133
|
def handle_unknown_cookies(cookie_names)
|
131
|
-
log_error("Request for '#{@request.url}' had unknown cookies: #{cookie_names.join(', ')}")
|
132
134
|
end
|
133
135
|
|
134
|
-
def
|
135
|
-
message = '** [SafeCookies
|
136
|
+
def log(error_message)
|
137
|
+
message = '** [SafeCookies] '
|
136
138
|
message << error_message
|
137
139
|
|
138
140
|
Rails.logger.error(message) if defined?(Rails)
|
@@ -13,7 +13,9 @@ module SafeCookies
|
|
13
13
|
end
|
14
14
|
|
15
15
|
class Configuration
|
16
|
-
|
16
|
+
attr_accessor :log_unknown_cookies
|
17
|
+
attr_reader :registered_cookies, :fix_cookie_paths, :correct_cookie_paths_timestamp,
|
18
|
+
:ignored_cookies
|
17
19
|
|
18
20
|
def initialize
|
19
21
|
self.registered_cookies = {}
|
@@ -72,7 +74,8 @@ module SafeCookies
|
|
72
74
|
private
|
73
75
|
|
74
76
|
attr_accessor :insecure_cookies, :scriptable_cookies
|
75
|
-
attr_writer :registered_cookies, :fix_cookie_paths, :correct_cookie_paths_timestamp,
|
77
|
+
attr_writer :registered_cookies, :fix_cookie_paths, :correct_cookie_paths_timestamp,
|
78
|
+
:ignored_cookies
|
76
79
|
|
77
80
|
end
|
78
81
|
|
data/lib/safe_cookies/version.rb
CHANGED
data/spec/safe_cookies_spec.rb
CHANGED
@@ -214,69 +214,79 @@ describe SafeCookies::Middleware do
|
|
214
214
|
# importance in the future.
|
215
215
|
context 'when a request has unknown cookies,' do
|
216
216
|
|
217
|
-
it '
|
217
|
+
it 'allows overwriting the handling mechanism' do
|
218
218
|
stub_app_call(app)
|
219
219
|
set_request_cookies(env, 'foo=bar')
|
220
220
|
|
221
|
-
subject.
|
221
|
+
def subject.handle_unknown_cookies(*args)
|
222
|
+
@custom_method_called = true
|
223
|
+
end
|
224
|
+
|
222
225
|
subject.call(env)
|
226
|
+
subject.instance_variable_get('@custom_method_called').should == true
|
223
227
|
end
|
224
228
|
|
225
|
-
|
226
|
-
|
227
|
-
|
229
|
+
context 'and it is configured to log unknown cookies' do
|
230
|
+
|
231
|
+
before do
|
232
|
+
SafeCookies.configure do |config|
|
233
|
+
config.log_unknown_cookies = true
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
it 'logs an error message' do
|
238
|
+
stub_app_call(app)
|
239
|
+
set_request_cookies(env, 'foo=bar')
|
228
240
|
|
229
|
-
|
241
|
+
subject.should_receive(:log).with(/unknown cookies: foo/)
|
242
|
+
subject.call(env)
|
243
|
+
end
|
244
|
+
|
245
|
+
it 'does not log an error if the (unregistered) cookie was initially set by the application' do
|
246
|
+
# application sets cookie
|
247
|
+
stub_app_call(app, :application_cookies => 'foo=bar; path=/some/path; secure')
|
248
|
+
|
249
|
+
code, headers, response = subject.call(env)
|
230
250
|
|
231
|
-
|
232
|
-
|
251
|
+
received_cookies = extract_cookies(headers['Set-Cookie'])
|
252
|
+
received_cookies.should include('foo=bar') # sanity check
|
233
253
|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
254
|
+
# client returns with the cookie, `app` and `subject` are different
|
255
|
+
# objects than in the previous request
|
256
|
+
other_app = stub('application')
|
257
|
+
other_subject = described_class.new(other_app)
|
238
258
|
|
239
|
-
|
240
|
-
|
259
|
+
stub_app_call(other_app)
|
260
|
+
set_request_cookies(env, *received_cookies)
|
241
261
|
|
242
|
-
|
243
|
-
|
244
|
-
end
|
245
|
-
|
246
|
-
it 'does not log an error if the cookie is listed in the cookie configuration' do
|
247
|
-
SafeCookies.configure do |config|
|
248
|
-
config.register_cookie('foo', :expire_after => 3600)
|
262
|
+
other_subject.should_not_receive(:log)
|
263
|
+
other_subject.call(env)
|
249
264
|
end
|
250
265
|
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
subject.call(env)
|
256
|
-
end
|
266
|
+
it 'does not log an error if the cookie is listed in the cookie configuration' do
|
267
|
+
SafeCookies.configure do |config|
|
268
|
+
config.register_cookie('foo', :expire_after => 3600)
|
269
|
+
end
|
257
270
|
|
258
|
-
|
259
|
-
|
260
|
-
config.ignore_cookie '__utma'
|
261
|
-
end
|
262
|
-
|
263
|
-
stub_app_call(app)
|
264
|
-
set_request_cookies(env, '__utma=tracking')
|
271
|
+
stub_app_call(app)
|
272
|
+
set_request_cookies(env, 'foo=bar')
|
265
273
|
|
266
|
-
|
267
|
-
|
268
|
-
|
274
|
+
subject.should_not_receive(:log)
|
275
|
+
subject.call(env)
|
276
|
+
end
|
269
277
|
|
270
|
-
|
271
|
-
|
272
|
-
|
278
|
+
it 'does not log an error if the cookie is ignored' do
|
279
|
+
SafeCookies.configure do |config|
|
280
|
+
config.ignore_cookie '__utma'
|
281
|
+
end
|
282
|
+
|
283
|
+
stub_app_call(app)
|
284
|
+
set_request_cookies(env, '__utma=tracking')
|
273
285
|
|
274
|
-
|
275
|
-
|
286
|
+
subject.should_not_receive(:log)
|
287
|
+
subject.call(env)
|
276
288
|
end
|
277
|
-
|
278
|
-
subject.call(env)
|
279
|
-
subject.instance_variable_get('@custom_method_called').should == true
|
289
|
+
|
280
290
|
end
|
281
291
|
|
282
292
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: safe_cookies
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dominik Schöler
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-11-
|
11
|
+
date: 2013-11-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -109,7 +109,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
109
109
|
version: '0'
|
110
110
|
requirements: []
|
111
111
|
rubyforge_project:
|
112
|
-
rubygems_version: 2.1.
|
112
|
+
rubygems_version: 2.1.2
|
113
113
|
signing_key:
|
114
114
|
specification_version: 4
|
115
115
|
summary: Make all cookies `secure` and `HttpOnly`.
|