secure_headers 5.2.0 → 6.0.0

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.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +8 -4
  3. data/CHANGELOG.md +3 -7
  4. data/Gemfile +1 -1
  5. data/README.md +2 -2
  6. data/docs/upgrading-to-6-0.md +50 -0
  7. data/lib/secure_headers/configuration.rb +114 -164
  8. data/lib/secure_headers/headers/clear_site_data.rb +1 -3
  9. data/lib/secure_headers/headers/content_security_policy.rb +8 -74
  10. data/lib/secure_headers/headers/content_security_policy_config.rb +3 -13
  11. data/lib/secure_headers/headers/expect_certificate_transparency.rb +2 -3
  12. data/lib/secure_headers/headers/policy_management.rb +14 -65
  13. data/lib/secure_headers/headers/public_key_pins.rb +2 -3
  14. data/lib/secure_headers/headers/referrer_policy.rb +2 -2
  15. data/lib/secure_headers/headers/strict_transport_security.rb +2 -2
  16. data/lib/secure_headers/headers/x_content_type_options.rb +2 -2
  17. data/lib/secure_headers/headers/x_download_options.rb +2 -2
  18. data/lib/secure_headers/headers/x_frame_options.rb +1 -2
  19. data/lib/secure_headers/headers/x_permitted_cross_domain_policies.rb +2 -2
  20. data/lib/secure_headers/headers/x_xss_protection.rb +3 -3
  21. data/lib/secure_headers/view_helper.rb +9 -8
  22. data/lib/secure_headers.rb +14 -78
  23. data/secure_headers.gemspec +1 -2
  24. data/spec/lib/secure_headers/configuration_spec.rb +15 -70
  25. data/spec/lib/secure_headers/headers/content_security_policy_spec.rb +2 -75
  26. data/spec/lib/secure_headers/headers/policy_management_spec.rb +35 -9
  27. data/spec/lib/secure_headers/middleware_spec.rb +7 -1
  28. data/spec/lib/secure_headers/view_helpers_spec.rb +29 -0
  29. data/spec/lib/secure_headers_spec.rb +38 -76
  30. data/spec/spec_helper.rb +7 -3
  31. metadata +3 -16
@@ -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, ContentSecurityPolicyConfig::CONFIG_KEY)
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, ContentSecurityPolicyConfig::CONFIG_KEY)
38
- SecureHeaders.opt_out_of_header(request, ContentSecurityPolicyReportOnlyConfig::CONFIG_KEY)
39
- SecureHeaders.opt_out_of_header(request, XContentTypeOptions::CONFIG_KEY)
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
 
@@ -105,27 +127,6 @@ module SecureHeaders
105
127
  expect(hash[XFrameOptions::HEADER_NAME]).to eq(XFrameOptions::SAMEORIGIN)
106
128
  end
107
129
 
108
- it "produces a UA-specific CSP when overriding (and busting the cache)" do
109
- Configuration.default do |config|
110
- config.csp = {
111
- default_src: %w('self'),
112
- script_src: %w('self'),
113
- child_src: %w('self')
114
- }
115
- end
116
- firefox_request = Rack::Request.new(request.env.merge("HTTP_USER_AGENT" => USER_AGENTS[:firefox]))
117
-
118
- # append an unsupported directive
119
- SecureHeaders.override_content_security_policy_directives(firefox_request, {plugin_types: %w(flash)})
120
- # append a supported directive
121
- SecureHeaders.override_content_security_policy_directives(firefox_request, {script_src: %w('self')})
122
-
123
- hash = SecureHeaders.header_hash_for(firefox_request)
124
-
125
- # child-src is translated to frame-src
126
- expect(hash[ContentSecurityPolicyConfig::HEADER_NAME]).to eq("default-src 'self'; frame-src 'self'; script-src 'self'")
127
- end
128
-
129
130
  it "produces a hash of headers with default config" do
130
131
  Configuration.default
131
132
  hash = SecureHeaders.header_hash_for(request)
@@ -175,22 +176,6 @@ module SecureHeaders
175
176
  expect(hash[ContentSecurityPolicyConfig::HEADER_NAME]).to eq("default-src 'self'; script-src mycdn.com 'unsafe-inline' anothercdn.com")
176
177
  end
177
178
 
178
- it "child-src and frame-src must match" do
179
- Configuration.default do |config|
180
- config.csp = {
181
- default_src: %w('self'),
182
- frame_src: %w(frame_src.com),
183
- script_src: %w('self')
184
- }
185
- end
186
-
187
- SecureHeaders.append_content_security_policy_directives(chrome_request, child_src: %w(child_src.com))
188
-
189
- expect {
190
- SecureHeaders.header_hash_for(chrome_request)
191
- }.to raise_error(ArgumentError)
192
- end
193
-
194
179
  it "supports named appends" do
195
180
  Configuration.default do |config|
196
181
  config.csp = {
@@ -265,21 +250,6 @@ module SecureHeaders
265
250
  expect(hash[ContentSecurityPolicyConfig::HEADER_NAME]).to eq("default-src https:; img-src data:; script-src 'self'")
266
251
  end
267
252
 
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
253
  it "appends a nonce to the script-src when used" do
284
254
  Configuration.default do |config|
285
255
  config.csp = {
@@ -297,21 +267,7 @@ module SecureHeaders
297
267
  SecureHeaders.content_security_policy_script_nonce(chrome_request)
298
268
 
299
269
  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}'")
270
+ expect(hash["Content-Security-Policy"]).to eq("default-src 'self'; script-src mycdn.com 'nonce-#{nonce}' 'unsafe-inline'; style-src 'self'")
315
271
  end
316
272
 
317
273
  it "does not support the deprecated `report_only: true` format" do
@@ -322,7 +278,7 @@ module SecureHeaders
322
278
  report_only: true
323
279
  }
324
280
  end
325
- }.to raise_error(ArgumentError)
281
+ }.to raise_error(ContentSecurityPolicyConfigError)
326
282
  end
327
283
 
328
284
  it "Raises an error if csp_report_only is used with `report_only: false`" do
@@ -349,6 +305,7 @@ module SecureHeaders
349
305
  end
350
306
 
351
307
  it "sets identical values when the configs are the same" do
308
+ reset_config
352
309
  Configuration.default do |config|
353
310
  config.csp = {
354
311
  default_src: %w('self'),
@@ -366,6 +323,7 @@ module SecureHeaders
366
323
  end
367
324
 
368
325
  it "sets different headers when the configs are different" do
326
+ reset_config
369
327
  Configuration.default do |config|
370
328
  config.csp = {
371
329
  default_src: %w('self'),
@@ -376,10 +334,11 @@ module SecureHeaders
376
334
 
377
335
  hash = SecureHeaders.header_hash_for(request)
378
336
  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 'self' foo.com")
337
+ expect(hash["Content-Security-Policy-Report-Only"]).to eq("default-src 'self'; script-src foo.com")
380
338
  end
381
339
 
382
340
  it "allows you to opt-out of enforced CSP" do
341
+ reset_config
383
342
  Configuration.default do |config|
384
343
  config.csp = SecureHeaders::OPT_OUT
385
344
  config.csp_report_only = {
@@ -437,6 +396,7 @@ module SecureHeaders
437
396
 
438
397
  context "when inferring which config to modify" do
439
398
  it "updates the enforced header when configured" do
399
+ reset_config
440
400
  Configuration.default do |config|
441
401
  config.csp = {
442
402
  default_src: %w('self'),
@@ -451,6 +411,7 @@ module SecureHeaders
451
411
  end
452
412
 
453
413
  it "updates the report only header when configured" do
414
+ reset_config
454
415
  Configuration.default do |config|
455
416
  config.csp = OPT_OUT
456
417
  config.csp_report_only = {
@@ -466,6 +427,7 @@ module SecureHeaders
466
427
  end
467
428
 
468
429
  it "updates both headers if both are configured" do
430
+ reset_config
469
431
  Configuration.default do |config|
470
432
  config.csp = {
471
433
  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 clear_configurations
43
- @configurations = nil
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.clear_configurations
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: 5.2.0
4
+ version: 6.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Neil Matatall
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-01-21 00:00:00.000000000 Z
11
+ date: 2018-05-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -24,20 +24,6 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
- - !ruby/object:Gem::Dependency
28
- name: useragent
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: 0.15.0
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: 0.15.0
41
27
  description: Manages application of security headers with many safe defaults.
42
28
  email:
43
29
  - neil.matatall@gmail.com
@@ -69,6 +55,7 @@ files:
69
55
  - docs/upgrading-to-3-0.md
70
56
  - docs/upgrading-to-4-0.md
71
57
  - docs/upgrading-to-5-0.md
58
+ - docs/upgrading-to-6-0.md
72
59
  - lib/secure_headers.rb
73
60
  - lib/secure_headers/configuration.rb
74
61
  - lib/secure_headers/hash_helper.rb