secure_headers 0.4.1 → 0.4.2
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.
Potentially problematic release.
This version of secure_headers might be problematic. Click here for more details.
- data/HISTORY.md +6 -0
- data/README.md +14 -4
- data/lib/secure_headers.rb +2 -2
- data/lib/secure_headers/headers/content_security_policy.rb +16 -1
- data/lib/secure_headers/headers/strict_transport_security.rb +1 -1
- data/lib/secure_headers/version.rb +1 -1
- data/spec/lib/secure_headers/headers/content_security_policy_spec.rb +32 -0
- data/spec/lib/secure_headers/headers/strict_transport_security_spec.rb +6 -0
- metadata +62 -48
data/HISTORY.md
CHANGED
data/README.md
CHANGED
@@ -41,7 +41,7 @@ By default, it will set all of the headers listed in the options section below u
|
|
41
41
|
|
42
42
|
Use the standard `skip_before_filter :filter_name, options` mechanism. e.g. `skip_before_filter :set_csp_header, :only => :tinymce_page`
|
43
43
|
|
44
|
-
The following methods are going to be called,
|
44
|
+
The following methods are going to be called, unless they are provided in a `skip_before_filter` block.
|
45
45
|
|
46
46
|
* `:set_csp_header`
|
47
47
|
* `:set_hsts_header`
|
@@ -53,10 +53,10 @@ The following methods are going to be called, unles they are provided in a `skip
|
|
53
53
|
|
54
54
|
This gem makes a few assumptions about how you will use some features. For example:
|
55
55
|
|
56
|
-
* It adds 'chrome-extension:' to your CSP directives by default. This helps drastically reduce the amount of reports, but you can also disable this feature by supplying
|
57
|
-
* It fills any blank directives with the value in
|
56
|
+
* It adds 'chrome-extension:' to your CSP directives by default. This helps drastically reduce the amount of reports, but you can also disable this feature by supplying `:disable_chrome_extension => true`.
|
57
|
+
* It fills any blank directives with the value in `:default_src` Getting a default\-src report is pretty useless. This way, you will always know what type of violation occurred. You can disable this feature by supplying `:disable_fill_missing => true`.
|
58
58
|
* It copies the connect\-src value to xhr\-src for AJAX requests when using Firefox.
|
59
|
-
* Firefox does not support cross\-origin CSP reports. If we are using Firefox, AND the value for
|
59
|
+
* Firefox does not support cross\-origin CSP reports. If we are using Firefox, AND the value for `:report_uri` does not satisfy the same\-origin requirements, we will instead forward to an internal endpoint (`FF_CSP_ENDPOINT`). This is also the case if `:report_uri` only contains a path, which we assume will be cross host. This endpoint will in turn forward the request to the value in `:forward_endpoint` without restriction. More information can be found in the "Note on Firefox handling of CSP" section.
|
60
60
|
|
61
61
|
|
62
62
|
## Configuration
|
@@ -159,6 +159,16 @@ and [Mozilla CSP specification](https://wiki.mozilla.org/Security/CSP/Specificat
|
|
159
159
|
:img_src => 'http://mycdn.example.com'
|
160
160
|
}
|
161
161
|
}
|
162
|
+
|
163
|
+
# script-nonce is an experimental feature of CSP 1.1 available in Chrome. It allows
|
164
|
+
# you to whitelist inline script blocks. For more information, see
|
165
|
+
# https://dvcs.w3.org/hg/content-security-policy/raw-file/tip/csp-specification.dev.html#script-nonce
|
166
|
+
:script_nonce => { 'abc123' }
|
167
|
+
|
168
|
+
# you can also use lambdas to use dynamically generated nonces
|
169
|
+
:script_nonce => lambda { @script_nonce] = 'something' }
|
170
|
+
# which can be used to whitelist a script block:
|
171
|
+
# script_tag :nonce = @script_nonce { inline_script_call() }
|
162
172
|
}
|
163
173
|
```
|
164
174
|
|
data/lib/secure_headers.rb
CHANGED
@@ -72,10 +72,10 @@ module SecureHeaders
|
|
72
72
|
options = self.class.options_for :csp, options
|
73
73
|
return if options == false
|
74
74
|
|
75
|
-
header = ContentSecurityPolicy.new(options, :request => request)
|
75
|
+
header = ContentSecurityPolicy.new(options, :request => request, :controller => self)
|
76
76
|
set_header(header.name, header.value)
|
77
77
|
if options && options[:experimental] && options[:enforce]
|
78
|
-
header = ContentSecurityPolicy.new(options, :experimental => true, :request => request)
|
78
|
+
header = ContentSecurityPolicy.new(options, :experimental => true, :request => request, :controller => self)
|
79
79
|
set_header(header.name, header.value)
|
80
80
|
end
|
81
81
|
end
|
@@ -36,6 +36,7 @@ module SecureHeaders
|
|
36
36
|
# :report used to determine what :ssl_request, :ua, and :request_uri are set to
|
37
37
|
def initialize(config=nil, options={})
|
38
38
|
@experimental = !!options.delete(:experimental)
|
39
|
+
@controller = options.delete(:controller)
|
39
40
|
if options[:request]
|
40
41
|
parse_request(options[:request])
|
41
42
|
else
|
@@ -65,6 +66,7 @@ module SecureHeaders
|
|
65
66
|
end
|
66
67
|
|
67
68
|
@report_uri = @config.delete(:report_uri)
|
69
|
+
@script_nonce = @config.delete(:script_nonce)
|
68
70
|
|
69
71
|
normalize_csp_options
|
70
72
|
normalize_reporting_endpoint
|
@@ -103,7 +105,8 @@ module SecureHeaders
|
|
103
105
|
header_value = [
|
104
106
|
build_impl_specific_directives,
|
105
107
|
generic_directives(@config),
|
106
|
-
report_uri_directive
|
108
|
+
report_uri_directive,
|
109
|
+
script_nonce_directive,
|
107
110
|
].join
|
108
111
|
|
109
112
|
#store the value for next time
|
@@ -208,6 +211,18 @@ module SecureHeaders
|
|
208
211
|
"report-uri #{@report_uri};"
|
209
212
|
end
|
210
213
|
|
214
|
+
def script_nonce_directive
|
215
|
+
return '' if @script_nonce.nil?
|
216
|
+
nonce_value = if @script_nonce.is_a?(String)
|
217
|
+
@script_nonce
|
218
|
+
elsif @controller
|
219
|
+
@controller.instance_exec(&@script_nonce)
|
220
|
+
else
|
221
|
+
@script_nonce.call
|
222
|
+
end
|
223
|
+
"script-nonce #{nonce_value};"
|
224
|
+
end
|
225
|
+
|
211
226
|
def generic_directives(config)
|
212
227
|
header_value = ''
|
213
228
|
if config[:img_src]
|
@@ -397,6 +397,38 @@ module SecureHeaders
|
|
397
397
|
end
|
398
398
|
end
|
399
399
|
end
|
400
|
+
|
401
|
+
context "when supplying a script nonce callback" do
|
402
|
+
let(:options) {
|
403
|
+
default_opts.merge({
|
404
|
+
:script_nonce => "random",
|
405
|
+
})
|
406
|
+
}
|
407
|
+
|
408
|
+
it "uses the value in the X-Webkit-CSP" do
|
409
|
+
csp = ContentSecurityPolicy.new(options, :request => request_for(CHROME))
|
410
|
+
csp.value.should match "script-nonce random;"
|
411
|
+
end
|
412
|
+
|
413
|
+
it "uses the value in the X-Content-Security-Policy" do
|
414
|
+
csp = ContentSecurityPolicy.new(options, :request => request_for(FIREFOX))
|
415
|
+
csp.value.should match "script-nonce random;"
|
416
|
+
end
|
417
|
+
|
418
|
+
it "runs a dynamic nonce generator" do
|
419
|
+
options[:script_nonce] = lambda { 'something' }
|
420
|
+
csp = ContentSecurityPolicy.new(options, :request => request_for(CHROME))
|
421
|
+
csp.value.should match "script-nonce something;"
|
422
|
+
end
|
423
|
+
|
424
|
+
it "runs against the given controller context" do
|
425
|
+
fake_params = {}
|
426
|
+
options[:script_nonce] = lambda { params[:script_nonce] = 'something' }
|
427
|
+
csp = ContentSecurityPolicy.new(options, :request => request_for(CHROME), :controller => double(:params => fake_params))
|
428
|
+
csp.value.should match "script-nonce something;"
|
429
|
+
fake_params.should == {:script_nonce => 'something'}
|
430
|
+
end
|
431
|
+
end
|
400
432
|
end
|
401
433
|
end
|
402
434
|
end
|
@@ -26,6 +26,12 @@ module SecureHeaders
|
|
26
26
|
s.value.should == "max-age=#{age}"
|
27
27
|
end
|
28
28
|
|
29
|
+
it "allows you to specify max-age as a Fixnum" do
|
30
|
+
age = 8675309
|
31
|
+
s = StrictTransportSecurity.new(:max_age => age)
|
32
|
+
s.value.should == "max-age=#{age}"
|
33
|
+
end
|
34
|
+
|
29
35
|
context "with an invalid configuration" do
|
30
36
|
context "with a hash argument" do
|
31
37
|
it "should allow string values for max-age" do
|
metadata
CHANGED
@@ -1,55 +1,62 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: secure_headers
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 11
|
5
5
|
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 4
|
9
|
+
- 2
|
10
|
+
version: 0.4.2
|
6
11
|
platform: ruby
|
7
|
-
authors:
|
12
|
+
authors:
|
8
13
|
- Neil Matatall
|
9
14
|
autorequire:
|
10
15
|
bindir: bin
|
11
16
|
cert_chain: []
|
12
|
-
|
13
|
-
|
14
|
-
|
17
|
+
|
18
|
+
date: 2013-05-05 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
15
21
|
name: brwsr
|
16
|
-
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
|
-
requirements:
|
19
|
-
- - ! '>='
|
20
|
-
- !ruby/object:Gem::Version
|
21
|
-
version: 1.1.1
|
22
|
-
type: :runtime
|
23
22
|
prerelease: false
|
24
|
-
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
24
|
none: false
|
26
|
-
requirements:
|
27
|
-
- -
|
28
|
-
- !ruby/object:Gem::Version
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 17
|
29
|
+
segments:
|
30
|
+
- 1
|
31
|
+
- 1
|
32
|
+
- 1
|
29
33
|
version: 1.1.1
|
30
|
-
|
34
|
+
type: :runtime
|
35
|
+
version_requirements: *id001
|
36
|
+
- !ruby/object:Gem::Dependency
|
31
37
|
name: rake
|
32
|
-
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
|
-
requirements:
|
35
|
-
- - ! '>='
|
36
|
-
- !ruby/object:Gem::Version
|
37
|
-
version: '0'
|
38
|
-
type: :development
|
39
38
|
prerelease: false
|
40
|
-
|
39
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
40
|
none: false
|
42
|
-
requirements:
|
43
|
-
- -
|
44
|
-
- !ruby/object:Gem::Version
|
45
|
-
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
hash: 3
|
45
|
+
segments:
|
46
|
+
- 0
|
47
|
+
version: "0"
|
48
|
+
type: :development
|
49
|
+
version_requirements: *id002
|
46
50
|
description: Add easily configured browser headers to responses.
|
47
|
-
email:
|
51
|
+
email:
|
48
52
|
- neil.matatall@gmail.com
|
49
53
|
executables: []
|
54
|
+
|
50
55
|
extensions: []
|
56
|
+
|
51
57
|
extra_rdoc_files: []
|
52
|
-
|
58
|
+
|
59
|
+
files:
|
53
60
|
- .gitignore
|
54
61
|
- .rvmrc
|
55
62
|
- .travis.yml
|
@@ -170,32 +177,39 @@ files:
|
|
170
177
|
- spec/spec_helper.rb
|
171
178
|
- travis.sh
|
172
179
|
homepage: https://github.com/twitter/secureheaders
|
173
|
-
licenses:
|
180
|
+
licenses:
|
174
181
|
- Apache Public License 2.0
|
175
182
|
post_install_message:
|
176
183
|
rdoc_options: []
|
177
|
-
|
184
|
+
|
185
|
+
require_paths:
|
178
186
|
- lib
|
179
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
187
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
180
188
|
none: false
|
181
|
-
requirements:
|
182
|
-
- -
|
183
|
-
- !ruby/object:Gem::Version
|
184
|
-
|
185
|
-
|
189
|
+
requirements:
|
190
|
+
- - ">="
|
191
|
+
- !ruby/object:Gem::Version
|
192
|
+
hash: 3
|
193
|
+
segments:
|
194
|
+
- 0
|
195
|
+
version: "0"
|
196
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
186
197
|
none: false
|
187
|
-
requirements:
|
188
|
-
- -
|
189
|
-
- !ruby/object:Gem::Version
|
190
|
-
|
198
|
+
requirements:
|
199
|
+
- - ">="
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
hash: 3
|
202
|
+
segments:
|
203
|
+
- 0
|
204
|
+
version: "0"
|
191
205
|
requirements: []
|
206
|
+
|
192
207
|
rubyforge_project:
|
193
208
|
rubygems_version: 1.8.24
|
194
209
|
signing_key:
|
195
210
|
specification_version: 3
|
196
|
-
summary: Add easily configured browser headers to responses including content security
|
197
|
-
|
198
|
-
test_files:
|
211
|
+
summary: Add easily configured browser headers to responses including content security policy, x-frame-options, strict-transport-security and more.
|
212
|
+
test_files:
|
199
213
|
- spec/controllers/content_security_policy_controller_spec.rb
|
200
214
|
- spec/lib/secure_headers/headers/content_security_policy_spec.rb
|
201
215
|
- spec/lib/secure_headers/headers/strict_transport_security_spec.rb
|