secure_headers 5.0.5 → 6.0.0.alpha01
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 +4 -4
- data/.travis.yml +8 -4
- data/CHANGELOG.md +4 -0
- data/docs/upgrading-to-6-0.md +50 -0
- data/lib/secure_headers/configuration.rb +114 -164
- data/lib/secure_headers/headers/clear_site_data.rb +1 -3
- data/lib/secure_headers/headers/content_security_policy.rb +2 -9
- data/lib/secure_headers/headers/content_security_policy_config.rb +3 -13
- data/lib/secure_headers/headers/expect_certificate_transparency.rb +2 -3
- data/lib/secure_headers/headers/policy_management.rb +12 -11
- data/lib/secure_headers/headers/public_key_pins.rb +2 -3
- data/lib/secure_headers/headers/referrer_policy.rb +2 -2
- data/lib/secure_headers/headers/strict_transport_security.rb +2 -2
- data/lib/secure_headers/headers/x_content_type_options.rb +2 -2
- data/lib/secure_headers/headers/x_download_options.rb +2 -2
- data/lib/secure_headers/headers/x_frame_options.rb +1 -2
- data/lib/secure_headers/headers/x_permitted_cross_domain_policies.rb +2 -2
- data/lib/secure_headers/headers/x_xss_protection.rb +3 -3
- data/lib/secure_headers.rb +14 -76
- data/secure_headers.gemspec +1 -1
- data/spec/lib/secure_headers/configuration_spec.rb +15 -70
- data/spec/lib/secure_headers/headers/content_security_policy_spec.rb +12 -12
- data/spec/lib/secure_headers/headers/policy_management_spec.rb +33 -7
- data/spec/lib/secure_headers/middleware_spec.rb +7 -1
- data/spec/lib/secure_headers/view_helpers_spec.rb +1 -0
- data/spec/lib/secure_headers_spec.rb +39 -40
- data/spec/spec_helper.rb +7 -3
- metadata +5 -4
|
@@ -17,10 +17,17 @@ module SecureHeaders
|
|
|
17
17
|
|
|
18
18
|
it "raises a NotYetConfiguredError if trying to opt-out of unconfigured headers" do
|
|
19
19
|
expect do
|
|
20
|
-
SecureHeaders.opt_out_of_header(request,
|
|
20
|
+
SecureHeaders.opt_out_of_header(request, :csp)
|
|
21
21
|
end.to raise_error(Configuration::NotYetConfiguredError)
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
+
it "raises a AlreadyConfiguredError if trying to configure and default has already been set " do
|
|
25
|
+
Configuration.default
|
|
26
|
+
expect do
|
|
27
|
+
Configuration.default
|
|
28
|
+
end.to raise_error(Configuration::AlreadyConfiguredError)
|
|
29
|
+
end
|
|
30
|
+
|
|
24
31
|
it "raises and ArgumentError when referencing an override that has not been set" do
|
|
25
32
|
expect do
|
|
26
33
|
Configuration.default
|
|
@@ -34,9 +41,9 @@ module SecureHeaders
|
|
|
34
41
|
config.csp = { default_src: %w('self'), script_src: %w('self')}
|
|
35
42
|
config.csp_report_only = config.csp
|
|
36
43
|
end
|
|
37
|
-
SecureHeaders.opt_out_of_header(request,
|
|
38
|
-
SecureHeaders.opt_out_of_header(request,
|
|
39
|
-
SecureHeaders.opt_out_of_header(request,
|
|
44
|
+
SecureHeaders.opt_out_of_header(request, :csp)
|
|
45
|
+
SecureHeaders.opt_out_of_header(request, :csp_report_only)
|
|
46
|
+
SecureHeaders.opt_out_of_header(request, :x_content_type_options)
|
|
40
47
|
hash = SecureHeaders.header_hash_for(request)
|
|
41
48
|
expect(hash["Content-Security-Policy-Report-Only"]).to be_nil
|
|
42
49
|
expect(hash["Content-Security-Policy"]).to be_nil
|
|
@@ -60,6 +67,24 @@ module SecureHeaders
|
|
|
60
67
|
expect(hash["X-Frame-Options"]).to be_nil
|
|
61
68
|
end
|
|
62
69
|
|
|
70
|
+
it "Overrides the current default config if default config changes during request" do
|
|
71
|
+
Configuration.default do |config|
|
|
72
|
+
config.x_frame_options = OPT_OUT
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Dynamically update the default config for this request
|
|
76
|
+
SecureHeaders.override_x_frame_options(request, "DENY")
|
|
77
|
+
|
|
78
|
+
Configuration.override(:dynamic_override) do |config|
|
|
79
|
+
config.x_content_type_options = "nosniff"
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
SecureHeaders.use_secure_headers_override(request, :dynamic_override)
|
|
83
|
+
hash = SecureHeaders.header_hash_for(request)
|
|
84
|
+
expect(hash["X-Content-Type-Options"]).to eq("nosniff")
|
|
85
|
+
expect(hash["X-Frame-Options"]).to eq("DENY")
|
|
86
|
+
end
|
|
87
|
+
|
|
63
88
|
it "allows you to opt out entirely" do
|
|
64
89
|
# configure the disabled-by-default headers to ensure they also do not get set
|
|
65
90
|
Configuration.default do |config|
|
|
@@ -78,9 +103,6 @@ module SecureHeaders
|
|
|
78
103
|
end
|
|
79
104
|
SecureHeaders.opt_out_of_all_protection(request)
|
|
80
105
|
hash = SecureHeaders.header_hash_for(request)
|
|
81
|
-
ALL_HEADER_CLASSES.each do |klass|
|
|
82
|
-
expect(hash[klass::CONFIG_KEY]).to be_nil
|
|
83
|
-
end
|
|
84
106
|
expect(hash.count).to eq(0)
|
|
85
107
|
end
|
|
86
108
|
|
|
@@ -116,7 +138,7 @@ module SecureHeaders
|
|
|
116
138
|
firefox_request = Rack::Request.new(request.env.merge("HTTP_USER_AGENT" => USER_AGENTS[:firefox]))
|
|
117
139
|
|
|
118
140
|
# append an unsupported directive
|
|
119
|
-
SecureHeaders.override_content_security_policy_directives(firefox_request, {plugin_types: %w(
|
|
141
|
+
SecureHeaders.override_content_security_policy_directives(firefox_request, {plugin_types: %w(application/pdf)})
|
|
120
142
|
# append a supported directive
|
|
121
143
|
SecureHeaders.override_content_security_policy_directives(firefox_request, {script_src: %w('self')})
|
|
122
144
|
|
|
@@ -265,21 +287,6 @@ module SecureHeaders
|
|
|
265
287
|
expect(hash[ContentSecurityPolicyConfig::HEADER_NAME]).to eq("default-src https:; img-src data:; script-src 'self'")
|
|
266
288
|
end
|
|
267
289
|
|
|
268
|
-
it "does not append a nonce when the browser does not support it" do
|
|
269
|
-
Configuration.default do |config|
|
|
270
|
-
config.csp = {
|
|
271
|
-
default_src: %w('self'),
|
|
272
|
-
script_src: %w(mycdn.com 'unsafe-inline'),
|
|
273
|
-
style_src: %w('self')
|
|
274
|
-
}
|
|
275
|
-
end
|
|
276
|
-
|
|
277
|
-
safari_request = Rack::Request.new(request.env.merge("HTTP_USER_AGENT" => USER_AGENTS[:safari5]))
|
|
278
|
-
SecureHeaders.content_security_policy_script_nonce(safari_request)
|
|
279
|
-
hash = SecureHeaders.header_hash_for(safari_request)
|
|
280
|
-
expect(hash[ContentSecurityPolicyConfig::HEADER_NAME]).to eq("default-src 'self'; script-src mycdn.com 'unsafe-inline'; style-src 'self'")
|
|
281
|
-
end
|
|
282
|
-
|
|
283
290
|
it "appends a nonce to the script-src when used" do
|
|
284
291
|
Configuration.default do |config|
|
|
285
292
|
config.csp = {
|
|
@@ -297,21 +304,7 @@ module SecureHeaders
|
|
|
297
304
|
SecureHeaders.content_security_policy_script_nonce(chrome_request)
|
|
298
305
|
|
|
299
306
|
hash = SecureHeaders.header_hash_for(chrome_request)
|
|
300
|
-
expect(hash["Content-Security-Policy"]).to eq("default-src 'self'; script-src mycdn.com 'nonce-#{nonce}'; style-src 'self'")
|
|
301
|
-
end
|
|
302
|
-
|
|
303
|
-
it "uses a nonce for safari 10+" do
|
|
304
|
-
Configuration.default do |config|
|
|
305
|
-
config.csp = {
|
|
306
|
-
default_src: %w('self'),
|
|
307
|
-
script_src: %w(mycdn.com)
|
|
308
|
-
}
|
|
309
|
-
end
|
|
310
|
-
|
|
311
|
-
safari_request = Rack::Request.new(request.env.merge("HTTP_USER_AGENT" => USER_AGENTS[:safari10]))
|
|
312
|
-
nonce = SecureHeaders.content_security_policy_script_nonce(safari_request)
|
|
313
|
-
hash = SecureHeaders.header_hash_for(safari_request)
|
|
314
|
-
expect(hash["Content-Security-Policy"]).to eq("default-src 'self'; script-src mycdn.com 'nonce-#{nonce}'")
|
|
307
|
+
expect(hash["Content-Security-Policy"]).to eq("default-src 'self'; script-src mycdn.com 'nonce-#{nonce}' 'unsafe-inline'; style-src 'self'")
|
|
315
308
|
end
|
|
316
309
|
|
|
317
310
|
it "does not support the deprecated `report_only: true` format" do
|
|
@@ -322,7 +315,7 @@ module SecureHeaders
|
|
|
322
315
|
report_only: true
|
|
323
316
|
}
|
|
324
317
|
end
|
|
325
|
-
}.to raise_error(
|
|
318
|
+
}.to raise_error(ContentSecurityPolicyConfigError)
|
|
326
319
|
end
|
|
327
320
|
|
|
328
321
|
it "Raises an error if csp_report_only is used with `report_only: false`" do
|
|
@@ -349,6 +342,7 @@ module SecureHeaders
|
|
|
349
342
|
end
|
|
350
343
|
|
|
351
344
|
it "sets identical values when the configs are the same" do
|
|
345
|
+
reset_config
|
|
352
346
|
Configuration.default do |config|
|
|
353
347
|
config.csp = {
|
|
354
348
|
default_src: %w('self'),
|
|
@@ -366,6 +360,7 @@ module SecureHeaders
|
|
|
366
360
|
end
|
|
367
361
|
|
|
368
362
|
it "sets different headers when the configs are different" do
|
|
363
|
+
reset_config
|
|
369
364
|
Configuration.default do |config|
|
|
370
365
|
config.csp = {
|
|
371
366
|
default_src: %w('self'),
|
|
@@ -376,10 +371,11 @@ module SecureHeaders
|
|
|
376
371
|
|
|
377
372
|
hash = SecureHeaders.header_hash_for(request)
|
|
378
373
|
expect(hash["Content-Security-Policy"]).to eq("default-src 'self'; script-src 'self'")
|
|
379
|
-
expect(hash["Content-Security-Policy-Report-Only"]).to eq("default-src 'self'; script-src
|
|
374
|
+
expect(hash["Content-Security-Policy-Report-Only"]).to eq("default-src 'self'; script-src foo.com")
|
|
380
375
|
end
|
|
381
376
|
|
|
382
377
|
it "allows you to opt-out of enforced CSP" do
|
|
378
|
+
reset_config
|
|
383
379
|
Configuration.default do |config|
|
|
384
380
|
config.csp = SecureHeaders::OPT_OUT
|
|
385
381
|
config.csp_report_only = {
|
|
@@ -437,6 +433,7 @@ module SecureHeaders
|
|
|
437
433
|
|
|
438
434
|
context "when inferring which config to modify" do
|
|
439
435
|
it "updates the enforced header when configured" do
|
|
436
|
+
reset_config
|
|
440
437
|
Configuration.default do |config|
|
|
441
438
|
config.csp = {
|
|
442
439
|
default_src: %w('self'),
|
|
@@ -451,6 +448,7 @@ module SecureHeaders
|
|
|
451
448
|
end
|
|
452
449
|
|
|
453
450
|
it "updates the report only header when configured" do
|
|
451
|
+
reset_config
|
|
454
452
|
Configuration.default do |config|
|
|
455
453
|
config.csp = OPT_OUT
|
|
456
454
|
config.csp_report_only = {
|
|
@@ -466,6 +464,7 @@ module SecureHeaders
|
|
|
466
464
|
end
|
|
467
465
|
|
|
468
466
|
it "updates both headers if both are configured" do
|
|
467
|
+
reset_config
|
|
469
468
|
Configuration.default do |config|
|
|
470
469
|
config.csp = {
|
|
471
470
|
default_src: %w(enforced.com),
|
data/spec/spec_helper.rb
CHANGED
|
@@ -26,6 +26,7 @@ USER_AGENTS = {
|
|
|
26
26
|
|
|
27
27
|
def expect_default_values(hash)
|
|
28
28
|
expect(hash[SecureHeaders::ContentSecurityPolicyConfig::HEADER_NAME]).to eq("default-src 'self' https:; font-src 'self' https: data:; img-src 'self' https: data:; object-src 'none'; script-src https:; style-src 'self' https: 'unsafe-inline'")
|
|
29
|
+
expect(hash[SecureHeaders::ContentSecurityPolicyReportOnlyConfig::HEADER_NAME]).to be_nil
|
|
29
30
|
expect(hash[SecureHeaders::XFrameOptions::HEADER_NAME]).to eq(SecureHeaders::XFrameOptions::DEFAULT_VALUE)
|
|
30
31
|
expect(hash[SecureHeaders::XDownloadOptions::HEADER_NAME]).to eq(SecureHeaders::XDownloadOptions::DEFAULT_VALUE)
|
|
31
32
|
expect(hash[SecureHeaders::StrictTransportSecurity::HEADER_NAME]).to eq(SecureHeaders::StrictTransportSecurity::DEFAULT_VALUE)
|
|
@@ -34,18 +35,21 @@ def expect_default_values(hash)
|
|
|
34
35
|
expect(hash[SecureHeaders::XPermittedCrossDomainPolicies::HEADER_NAME]).to eq(SecureHeaders::XPermittedCrossDomainPolicies::DEFAULT_VALUE)
|
|
35
36
|
expect(hash[SecureHeaders::ReferrerPolicy::HEADER_NAME]).to be_nil
|
|
36
37
|
expect(hash[SecureHeaders::ExpectCertificateTransparency::HEADER_NAME]).to be_nil
|
|
38
|
+
expect(hash[SecureHeaders::ClearSiteData::HEADER_NAME]).to be_nil
|
|
39
|
+
expect(hash[SecureHeaders::ExpectCertificateTransparency::HEADER_NAME]).to be_nil
|
|
40
|
+
expect(hash[SecureHeaders::PublicKeyPins::HEADER_NAME]).to be_nil
|
|
37
41
|
end
|
|
38
42
|
|
|
39
43
|
module SecureHeaders
|
|
40
44
|
class Configuration
|
|
41
45
|
class << self
|
|
42
|
-
def
|
|
43
|
-
|
|
46
|
+
def clear_default_config
|
|
47
|
+
remove_instance_variable(:@default_config) if defined?(@default_config)
|
|
44
48
|
end
|
|
45
49
|
end
|
|
46
50
|
end
|
|
47
51
|
end
|
|
48
52
|
|
|
49
53
|
def reset_config
|
|
50
|
-
SecureHeaders::Configuration.
|
|
54
|
+
SecureHeaders::Configuration.clear_default_config
|
|
51
55
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: secure_headers
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 6.0.0.alpha01
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Neil Matatall
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2018-02-
|
|
11
|
+
date: 2018-02-13 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rake
|
|
@@ -69,6 +69,7 @@ files:
|
|
|
69
69
|
- docs/upgrading-to-3-0.md
|
|
70
70
|
- docs/upgrading-to-4-0.md
|
|
71
71
|
- docs/upgrading-to-5-0.md
|
|
72
|
+
- docs/upgrading-to-6-0.md
|
|
72
73
|
- lib/secure_headers.rb
|
|
73
74
|
- lib/secure_headers/configuration.rb
|
|
74
75
|
- lib/secure_headers/hash_helper.rb
|
|
@@ -125,9 +126,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
125
126
|
version: '0'
|
|
126
127
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
127
128
|
requirements:
|
|
128
|
-
- - "
|
|
129
|
+
- - ">"
|
|
129
130
|
- !ruby/object:Gem::Version
|
|
130
|
-
version:
|
|
131
|
+
version: 1.3.1
|
|
131
132
|
requirements: []
|
|
132
133
|
rubyforge_project:
|
|
133
134
|
rubygems_version: 2.6.13
|