safe_cookies 0.2.0 → 0.2.1
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.
- 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`.
|