secure_headers 6.0.0 → 6.7.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 (38) hide show
  1. checksums.yaml +5 -5
  2. data/.github/dependabot.yml +6 -0
  3. data/.github/workflows/build.yml +24 -0
  4. data/.github/workflows/github-release.yml +28 -0
  5. data/.rubocop.yml +1 -0
  6. data/.ruby-version +1 -1
  7. data/CHANGELOG.md +47 -1
  8. data/Gemfile +4 -1
  9. data/LICENSE +1 -1
  10. data/README.md +70 -30
  11. data/docs/cookies.md +5 -4
  12. data/docs/named_overrides_and_appends.md +3 -6
  13. data/docs/per_action_configuration.md +2 -4
  14. data/docs/upgrading-to-6-0.md +4 -4
  15. data/lib/secure_headers/configuration.rb +24 -16
  16. data/lib/secure_headers/headers/content_security_policy.rb +34 -41
  17. data/lib/secure_headers/headers/content_security_policy_config.rb +15 -48
  18. data/lib/secure_headers/headers/cookie.rb +9 -3
  19. data/lib/secure_headers/headers/policy_management.rb +92 -17
  20. data/lib/secure_headers/middleware.rb +0 -6
  21. data/lib/secure_headers/utils/cookies_config.rb +7 -5
  22. data/lib/secure_headers/version.rb +5 -0
  23. data/lib/secure_headers/view_helper.rb +11 -10
  24. data/lib/secure_headers.rb +3 -11
  25. data/lib/tasks/tasks.rake +6 -7
  26. data/secure_headers.gemspec +9 -5
  27. data/spec/lib/secure_headers/configuration_spec.rb +54 -0
  28. data/spec/lib/secure_headers/headers/content_security_policy_spec.rb +98 -8
  29. data/spec/lib/secure_headers/headers/cookie_spec.rb +22 -25
  30. data/spec/lib/secure_headers/headers/policy_management_spec.rb +29 -19
  31. data/spec/lib/secure_headers/middleware_spec.rb +0 -19
  32. data/spec/lib/secure_headers/view_helpers_spec.rb +5 -4
  33. data/spec/lib/secure_headers_spec.rb +0 -35
  34. data/spec/spec_helper.rb +10 -1
  35. metadata +13 -12
  36. data/.travis.yml +0 -29
  37. data/lib/secure_headers/headers/public_key_pins.rb +0 -81
  38. data/spec/lib/secure_headers/headers/public_key_pins_spec.rb +0 -38
@@ -1,16 +1,20 @@
1
- # -*- encoding: utf-8 -*-
2
1
  # frozen_string_literal: true
2
+
3
+ lib = File.expand_path("../lib", __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require "secure_headers/version"
6
+
3
7
  Gem::Specification.new do |gem|
4
8
  gem.name = "secure_headers"
5
- gem.version = "6.0.0"
9
+ gem.version = SecureHeaders::VERSION
6
10
  gem.authors = ["Neil Matatall"]
7
11
  gem.email = ["neil.matatall@gmail.com"]
8
- gem.description = "Manages application of security headers with many safe defaults."
9
- gem.summary = 'Add easily configured security headers to responses
12
+ gem.summary = "Manages application of security headers with many safe defaults."
13
+ gem.description = 'Add easily configured security headers to responses
10
14
  including content-security-policy, x-frame-options,
11
15
  strict-transport-security, etc.'
12
16
  gem.homepage = "https://github.com/twitter/secureheaders"
13
- gem.license = "Apache Public License 2.0"
17
+ gem.license = "MIT"
14
18
  gem.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
15
19
  gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
16
20
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
@@ -34,6 +34,60 @@ module SecureHeaders
34
34
  expect(Configuration.overrides(:test_override)).to_not be_nil
35
35
  end
36
36
 
37
+ describe "#override" do
38
+ it "raises on configuring an existing override" do
39
+ set_override = Proc.new {
40
+ Configuration.override(:test_override) do |config|
41
+ config.x_frame_options = "DENY"
42
+ end
43
+ }
44
+
45
+ set_override.call
46
+
47
+ expect { set_override.call }
48
+ .to raise_error(Configuration::AlreadyConfiguredError, "Configuration already exists")
49
+ end
50
+
51
+ it "raises when a named append with the given name exists" do
52
+ Configuration.named_append(:test_override) do |config|
53
+ config.x_frame_options = "DENY"
54
+ end
55
+
56
+ expect do
57
+ Configuration.override(:test_override) do |config|
58
+ config.x_frame_options = "SAMEORIGIN"
59
+ end
60
+ end.to raise_error(Configuration::AlreadyConfiguredError, "Configuration already exists")
61
+ end
62
+ end
63
+
64
+ describe "#named_append" do
65
+ it "raises on configuring an existing append" do
66
+ set_override = Proc.new {
67
+ Configuration.named_append(:test_override) do |config|
68
+ config.x_frame_options = "DENY"
69
+ end
70
+ }
71
+
72
+ set_override.call
73
+
74
+ expect { set_override.call }
75
+ .to raise_error(Configuration::AlreadyConfiguredError, "Configuration already exists")
76
+ end
77
+
78
+ it "raises when an override with the given name exists" do
79
+ Configuration.override(:test_override) do |config|
80
+ config.x_frame_options = "DENY"
81
+ end
82
+
83
+ expect do
84
+ Configuration.named_append(:test_override) do |config|
85
+ config.x_frame_options = "SAMEORIGIN"
86
+ end
87
+ end.to raise_error(Configuration::AlreadyConfiguredError, "Configuration already exists")
88
+ end
89
+ end
90
+
37
91
  it "deprecates the secure_cookies configuration" do
38
92
  expect {
39
93
  Configuration.default do |config|
@@ -28,6 +28,16 @@ module SecureHeaders
28
28
  expect(ContentSecurityPolicy.new.value).to eq("default-src https:; form-action 'self'; img-src https: data: 'self'; object-src 'none'; script-src https:; style-src 'self' 'unsafe-inline' https:")
29
29
  end
30
30
 
31
+ it "deprecates and escapes semicolons in directive source lists" do
32
+ expect(Kernel).to receive(:warn).with(%(frame_ancestors contains a ; in "google.com;script-src *;.;" which will raise an error in future versions. It has been replaced with a blank space.))
33
+ expect(ContentSecurityPolicy.new(frame_ancestors: %w(https://google.com;script-src https://*;.;)).value).to eq("frame-ancestors google.com script-src * .")
34
+ end
35
+
36
+ it "deprecates and escapes semicolons in directive source lists" do
37
+ expect(Kernel).to receive(:warn).with(%(frame_ancestors contains a \n in "\\nfoo.com\\nhacked" which will raise an error in future versions. It has been replaced with a blank space.))
38
+ expect(ContentSecurityPolicy.new(frame_ancestors: ["\nfoo.com\nhacked"]).value).to eq("frame-ancestors foo.com hacked")
39
+ end
40
+
31
41
  it "discards 'none' values if any other source expressions are present" do
32
42
  csp = ContentSecurityPolicy.new(default_opts.merge(child_src: %w('self' 'none')))
33
43
  expect(csp.value).not_to include("'none'")
@@ -38,12 +48,12 @@ module SecureHeaders
38
48
  expect(csp.value).to eq("default-src * 'unsafe-inline' 'unsafe-eval' data: blob:")
39
49
  end
40
50
 
41
- it "minifies source expressions based on overlapping wildcards" do
51
+ it "does not minify source expressions based on overlapping wildcards" do
42
52
  config = {
43
53
  default_src: %w(a.example.org b.example.org *.example.org https://*.example.org)
44
54
  }
45
55
  csp = ContentSecurityPolicy.new(config)
46
- expect(csp.value).to eq("default-src *.example.org")
56
+ expect(csp.value).to eq("default-src a.example.org b.example.org *.example.org")
47
57
  end
48
58
 
49
59
  it "removes http/s schemes from hosts" do
@@ -82,20 +92,30 @@ module SecureHeaders
82
92
  end
83
93
 
84
94
  it "does add a boolean directive if the value is true" do
85
- csp = ContentSecurityPolicy.new(default_src: ["https://example.org"], block_all_mixed_content: true, upgrade_insecure_requests: true)
86
- expect(csp.value).to eq("default-src example.org; block-all-mixed-content; upgrade-insecure-requests")
95
+ csp = ContentSecurityPolicy.new(default_src: ["https://example.org"], upgrade_insecure_requests: true)
96
+ expect(csp.value).to eq("default-src example.org; upgrade-insecure-requests")
87
97
  end
88
98
 
89
99
  it "does not add a boolean directive if the value is false" do
90
- csp = ContentSecurityPolicy.new(default_src: ["https://example.org"], block_all_mixed_content: true, upgrade_insecure_requests: false)
91
- expect(csp.value).to eq("default-src example.org; block-all-mixed-content")
100
+ csp = ContentSecurityPolicy.new(default_src: ["https://example.org"], upgrade_insecure_requests: false)
101
+ expect(csp.value).to eq("default-src example.org")
92
102
  end
93
103
 
94
- it "deduplicates any source expressions" do
95
- csp = ContentSecurityPolicy.new(default_src: %w(example.org example.org example.org))
104
+ it "handles wildcard subdomain with wildcard port" do
105
+ csp = ContentSecurityPolicy.new(default_src: %w(https://*.example.org:*))
106
+ expect(csp.value).to eq("default-src *.example.org:*")
107
+ end
108
+
109
+ it "deduplicates source expressions that match exactly (after scheme stripping)" do
110
+ csp = ContentSecurityPolicy.new(default_src: %w(example.org https://example.org example.org))
96
111
  expect(csp.value).to eq("default-src example.org")
97
112
  end
98
113
 
114
+ it "does not deduplicate non-matching schema source expressions" do
115
+ csp = ContentSecurityPolicy.new(default_src: %w(*.example.org wss://example.example.org))
116
+ expect(csp.value).to eq("default-src *.example.org wss://example.example.org")
117
+ end
118
+
99
119
  it "creates maximally strict sandbox policy when passed no sandbox token values" do
100
120
  csp = ContentSecurityPolicy.new(default_src: %w(example.org), sandbox: [])
101
121
  expect(csp.value).to eq("default-src example.org; sandbox")
@@ -116,10 +136,80 @@ module SecureHeaders
116
136
  ContentSecurityPolicy.new(default_src: %w('self'), frame_src: %w('self')).value
117
137
  end
118
138
 
139
+ it "allows script as a require-sri-src" do
140
+ csp = ContentSecurityPolicy.new(default_src: %w('self'), require_sri_for: %w(script))
141
+ expect(csp.value).to eq("default-src 'self'; require-sri-for script")
142
+ end
143
+
144
+ it "allows style as a require-sri-src" do
145
+ csp = ContentSecurityPolicy.new(default_src: %w('self'), require_sri_for: %w(style))
146
+ expect(csp.value).to eq("default-src 'self'; require-sri-for style")
147
+ end
148
+
149
+ it "allows script and style as a require-sri-src" do
150
+ csp = ContentSecurityPolicy.new(default_src: %w('self'), require_sri_for: %w(script style))
151
+ expect(csp.value).to eq("default-src 'self'; require-sri-for script style")
152
+ end
153
+
154
+ it "allows style as a require-trusted-types-for source" do
155
+ csp = ContentSecurityPolicy.new(default_src: %w('self'), require_trusted_types_for: %w(script))
156
+ expect(csp.value).to eq("default-src 'self'; require-trusted-types-for script")
157
+ end
158
+
159
+ it "includes prefetch-src" do
160
+ csp = ContentSecurityPolicy.new(default_src: %w('self'), prefetch_src: %w(foo.com))
161
+ expect(csp.value).to eq("default-src 'self'; prefetch-src foo.com")
162
+ end
163
+
164
+ it "includes navigate-to" do
165
+ csp = ContentSecurityPolicy.new(default_src: %w('self'), navigate_to: %w(foo.com))
166
+ expect(csp.value).to eq("default-src 'self'; navigate-to foo.com")
167
+ end
168
+
119
169
  it "supports strict-dynamic" do
120
170
  csp = ContentSecurityPolicy.new({default_src: %w('self'), script_src: [ContentSecurityPolicy::STRICT_DYNAMIC], script_nonce: 123456})
121
171
  expect(csp.value).to eq("default-src 'self'; script-src 'strict-dynamic' 'nonce-123456' 'unsafe-inline'")
122
172
  end
173
+
174
+ it "supports strict-dynamic and opting out of the appended 'unsafe-inline'" do
175
+ csp = ContentSecurityPolicy.new({default_src: %w('self'), script_src: [ContentSecurityPolicy::STRICT_DYNAMIC], script_nonce: 123456, disable_nonce_backwards_compatibility: true })
176
+ expect(csp.value).to eq("default-src 'self'; script-src 'strict-dynamic' 'nonce-123456'")
177
+ end
178
+
179
+ it "supports script-src-elem directive" do
180
+ csp = ContentSecurityPolicy.new({script_src: %w('self'), script_src_elem: %w('self')})
181
+ expect(csp.value).to eq("script-src 'self'; script-src-elem 'self'")
182
+ end
183
+
184
+ it "supports script-src-attr directive" do
185
+ csp = ContentSecurityPolicy.new({script_src: %w('self'), script_src_attr: %w('self')})
186
+ expect(csp.value).to eq("script-src 'self'; script-src-attr 'self'")
187
+ end
188
+
189
+ it "supports style-src-elem directive" do
190
+ csp = ContentSecurityPolicy.new({style_src: %w('self'), style_src_elem: %w('self')})
191
+ expect(csp.value).to eq("style-src 'self'; style-src-elem 'self'")
192
+ end
193
+
194
+ it "supports style-src-attr directive" do
195
+ csp = ContentSecurityPolicy.new({style_src: %w('self'), style_src_attr: %w('self')})
196
+ expect(csp.value).to eq("style-src 'self'; style-src-attr 'self'")
197
+ end
198
+
199
+ it "supports trusted-types directive" do
200
+ csp = ContentSecurityPolicy.new({trusted_types: %w(blahblahpolicy)})
201
+ expect(csp.value).to eq("trusted-types blahblahpolicy")
202
+ end
203
+
204
+ it "supports trusted-types directive with 'none'" do
205
+ csp = ContentSecurityPolicy.new({trusted_types: %w('none')})
206
+ expect(csp.value).to eq("trusted-types 'none'")
207
+ end
208
+
209
+ it "allows duplicate policy names in trusted-types directive" do
210
+ csp = ContentSecurityPolicy.new({trusted_types: %w(blahblahpolicy 'allow-duplicates')})
211
+ expect(csp.value).to eq("trusted-types blahblahpolicy 'allow-duplicates'")
212
+ end
123
213
  end
124
214
  end
125
215
  end
@@ -68,29 +68,21 @@ module SecureHeaders
68
68
  end
69
69
 
70
70
  context "SameSite cookies" do
71
- it "flags SameSite=Lax" do
72
- cookie = Cookie.new(raw_cookie, samesite: { lax: { only: ["_session"] } }, secure: OPT_OUT, httponly: OPT_OUT)
73
- expect(cookie.to_s).to eq("_session=thisisatest; SameSite=Lax")
74
- end
75
-
76
- it "flags SameSite=Lax when configured with a boolean" do
77
- cookie = Cookie.new(raw_cookie, samesite: { lax: true}, secure: OPT_OUT, httponly: OPT_OUT)
78
- expect(cookie.to_s).to eq("_session=thisisatest; SameSite=Lax")
79
- end
80
-
81
- it "does not flag cookies as SameSite=Lax when excluded" do
82
- cookie = Cookie.new(raw_cookie, samesite: { lax: { except: ["_session"] } }, secure: OPT_OUT, httponly: OPT_OUT)
83
- expect(cookie.to_s).to eq("_session=thisisatest")
84
- end
71
+ %w(None Lax Strict).each do |flag|
72
+ it "flags SameSite=#{flag}" do
73
+ cookie = Cookie.new(raw_cookie, samesite: { flag.downcase.to_sym => { only: ["_session"] } }, secure: OPT_OUT, httponly: OPT_OUT)
74
+ expect(cookie.to_s).to eq("_session=thisisatest; SameSite=#{flag}")
75
+ end
85
76
 
86
- it "flags SameSite=Strict" do
87
- cookie = Cookie.new(raw_cookie, samesite: { strict: { only: ["_session"] } }, secure: OPT_OUT, httponly: OPT_OUT)
88
- expect(cookie.to_s).to eq("_session=thisisatest; SameSite=Strict")
89
- end
77
+ it "flags SameSite=#{flag} when configured with a boolean" do
78
+ cookie = Cookie.new(raw_cookie, samesite: { flag.downcase.to_sym => true}, secure: OPT_OUT, httponly: OPT_OUT)
79
+ expect(cookie.to_s).to eq("_session=thisisatest; SameSite=#{flag}")
80
+ end
90
81
 
91
- it "does not flag cookies as SameSite=Strict when excluded" do
92
- cookie = Cookie.new(raw_cookie, samesite: { strict: { except: ["_session"] }}, secure: OPT_OUT, httponly: OPT_OUT)
93
- expect(cookie.to_s).to eq("_session=thisisatest")
82
+ it "does not flag cookies as SameSite=#{flag} when excluded" do
83
+ cookie = Cookie.new(raw_cookie, samesite: { flag.downcase.to_sym => { except: ["_session"] } }, secure: OPT_OUT, httponly: OPT_OUT)
84
+ expect(cookie.to_s).to eq("_session=thisisatest")
85
+ end
94
86
  end
95
87
 
96
88
  it "flags SameSite=Strict when configured with a boolean" do
@@ -149,10 +141,15 @@ module SecureHeaders
149
141
  end.to raise_error(CookiesConfigError)
150
142
  end
151
143
 
152
- it "raises an exception when SameSite lax and strict enforcement modes are configured with booleans" do
153
- expect do
154
- Cookie.validate_config!(samesite: { lax: true, strict: true})
155
- end.to raise_error(CookiesConfigError)
144
+ cookie_options = %i(none lax strict)
145
+ cookie_options.each do |flag|
146
+ (cookie_options - [flag]).each do |other_flag|
147
+ it "raises an exception when SameSite #{flag} and #{other_flag} enforcement modes are configured with booleans" do
148
+ expect do
149
+ Cookie.validate_config!(samesite: { flag => true, other_flag => true})
150
+ end.to raise_error(CookiesConfigError)
151
+ end
152
+ end
156
153
  end
157
154
 
158
155
  it "raises an exception when SameSite lax and strict enforcement modes are configured with booleans" do
@@ -28,24 +28,34 @@ module SecureHeaders
28
28
 
29
29
  # directive values: these values will directly translate into source directives
30
30
  default_src: %w(https: 'self'),
31
- frame_src: %w('self' *.twimg.com itunes.apple.com),
32
- child_src: %w('self' *.twimg.com itunes.apple.com),
31
+
32
+ base_uri: %w('self'),
33
33
  connect_src: %w(wss:),
34
+ child_src: %w('self' *.twimg.com itunes.apple.com),
34
35
  font_src: %w('self' data:),
36
+ form_action: %w('self' github.com),
37
+ frame_ancestors: %w('none'),
38
+ frame_src: %w('self' *.twimg.com itunes.apple.com),
35
39
  img_src: %w(mycdn.com data:),
36
40
  manifest_src: %w(manifest.com),
37
41
  media_src: %w(utoob.com),
42
+ navigate_to: %w(netscape.com),
38
43
  object_src: %w('self'),
44
+ plugin_types: %w(application/x-shockwave-flash),
45
+ prefetch_src: %w(fetch.com),
46
+ require_sri_for: %w(script style),
47
+ require_trusted_types_for: %w('script'),
39
48
  script_src: %w('self'),
40
49
  style_src: %w('unsafe-inline'),
41
- worker_src: %w(worker.com),
42
- base_uri: %w('self'),
43
- form_action: %w('self' github.com),
44
- frame_ancestors: %w('none'),
45
- plugin_types: %w(application/x-shockwave-flash),
46
- block_all_mixed_content: true, # see [http://www.w3.org/TR/mixed-content/](http://www.w3.org/TR/mixed-content/)
47
50
  upgrade_insecure_requests: true, # see https://www.w3.org/TR/upgrade-insecure-requests/
48
- report_uri: %w(https://example.com/uri-directive)
51
+ worker_src: %w(worker.com),
52
+ script_src_elem: %w(example.com),
53
+ script_src_attr: %w(example.com),
54
+ style_src_elem: %w(example.com),
55
+ style_src_attr: %w(example.com),
56
+ trusted_types: %w(abcpolicy),
57
+
58
+ report_uri: %w(https://example.com/uri-directive),
49
59
  }
50
60
 
51
61
  ContentSecurityPolicy.validate_config!(ContentSecurityPolicyConfig.new(config))
@@ -81,12 +91,6 @@ module SecureHeaders
81
91
  end.to raise_error(ContentSecurityPolicyConfigError)
82
92
  end
83
93
 
84
- it "requires :block_all_mixed_content to be a boolean value" do
85
- expect do
86
- ContentSecurityPolicy.validate_config!(ContentSecurityPolicyConfig.new(default_opts.merge(block_all_mixed_content: "steve")))
87
- end.to raise_error(ContentSecurityPolicyConfigError)
88
- end
89
-
90
94
  it "requires :upgrade_insecure_requests to be a boolean value" do
91
95
  expect do
92
96
  ContentSecurityPolicy.validate_config!(ContentSecurityPolicyConfig.new(default_opts.merge(upgrade_insecure_requests: "steve")))
@@ -111,6 +115,12 @@ module SecureHeaders
111
115
  end.to raise_error(ContentSecurityPolicyConfigError)
112
116
  end
113
117
 
118
+ it "rejects style for trusted types" do
119
+ expect do
120
+ ContentSecurityPolicy.validate_config!(ContentSecurityPolicyConfig.new(default_opts.merge(style_src: %w('self'), require_trusted_types_for: %w(script style), trusted_types: %w(abcpolicy))))
121
+ end
122
+ end
123
+
114
124
  # this is mostly to ensure people don't use the antiquated shorthands common in other configs
115
125
  it "performs light validation on source lists" do
116
126
  expect do
@@ -227,18 +237,18 @@ module SecureHeaders
227
237
  expect(csp.name).to eq(ContentSecurityPolicyReportOnlyConfig::HEADER_NAME)
228
238
  end
229
239
 
230
- it "overrides the :block_all_mixed_content flag" do
240
+ it "overrides the :upgrade_insecure_requests flag" do
231
241
  Configuration.default do |config|
232
242
  config.csp = {
233
243
  default_src: %w(https:),
234
244
  script_src: %w('self'),
235
- block_all_mixed_content: false
245
+ upgrade_insecure_requests: false
236
246
  }
237
247
  end
238
248
  default_policy = Configuration.dup
239
- combined_config = ContentSecurityPolicy.combine_policies(default_policy.csp.to_h, block_all_mixed_content: true)
249
+ combined_config = ContentSecurityPolicy.combine_policies(default_policy.csp.to_h, upgrade_insecure_requests: true)
240
250
  csp = ContentSecurityPolicy.new(combined_config)
241
- expect(csp.value).to eq("default-src https:; block-all-mixed-content; script-src 'self'")
251
+ expect(csp.value).to eq("default-src https:; script-src 'self'; upgrade-insecure-requests")
242
252
  end
243
253
 
244
254
  it "raises an error if appending to a OPT_OUT policy" do
@@ -14,25 +14,6 @@ module SecureHeaders
14
14
  Configuration.default
15
15
  end
16
16
 
17
- it "warns if the hpkp report-uri host is the same as the current host" do
18
- report_host = "report-uri.io"
19
- reset_config
20
- Configuration.default do |config|
21
- config.hpkp = {
22
- max_age: 10000000,
23
- pins: [
24
- {sha256: "b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c"},
25
- {sha256: "73a2c64f9545172c1195efb6616ca5f7afd1df6f245407cafb90de3998a1c97f"}
26
- ],
27
- report_uri: "https://#{report_host}/example-hpkp"
28
- }
29
- end
30
-
31
- expect(Kernel).to receive(:warn).with(Middleware::HPKP_SAME_HOST_WARNING)
32
-
33
- middleware.call(Rack::MockRequest.env_for("https://#{report_host}", {}))
34
- end
35
-
36
17
  it "sets the headers" do
37
18
  _, env = middleware.call(Rack::MockRequest.env_for("https://looocalhost", {}))
38
19
  expect_default_values(env)
@@ -6,7 +6,7 @@ class Message < ERB
6
6
  include SecureHeaders::ViewHelpers
7
7
 
8
8
  def self.template
9
- <<-TEMPLATE
9
+ <<-TEMPLATE
10
10
  <% hashed_javascript_tag(raise_error_on_unrecognized_hash = true) do %>
11
11
  console.log(1)
12
12
  <% end %>
@@ -62,9 +62,10 @@ TEMPLATE
62
62
  end
63
63
 
64
64
  def content_tag(type, content = nil, options = nil, &block)
65
- content = if block_given?
66
- capture(block)
67
- end
65
+ content =
66
+ if block_given?
67
+ capture(block)
68
+ end
68
69
 
69
70
  if options.is_a?(Hash)
70
71
  options = options.map { |k, v| " #{k}=#{v}" }
@@ -90,16 +90,6 @@ module SecureHeaders
90
90
  Configuration.default do |config|
91
91
  config.csp = { default_src: ["example.com"], script_src: %w('self') }
92
92
  config.csp_report_only = config.csp
93
- config.hpkp = {
94
- report_only: false,
95
- max_age: 10000000,
96
- include_subdomains: true,
97
- report_uri: "https://report-uri.io/example-hpkp",
98
- pins: [
99
- {sha256: "abc"},
100
- {sha256: "123"}
101
- ]
102
- }
103
93
  end
104
94
  SecureHeaders.opt_out_of_all_protection(request)
105
95
  hash = SecureHeaders.header_hash_for(request)
@@ -141,23 +131,6 @@ module SecureHeaders
141
131
  expect(SecureHeaders.header_hash_for(plaintext_request)[StrictTransportSecurity::HEADER_NAME]).to be_nil
142
132
  end
143
133
 
144
- it "does not set the HPKP header if request is over HTTP" do
145
- plaintext_request = Rack::Request.new({})
146
- Configuration.default do |config|
147
- config.hpkp = {
148
- max_age: 1_000_000,
149
- include_subdomains: true,
150
- report_uri: "//example.com/uri-directive",
151
- pins: [
152
- { sha256: "abc" },
153
- { sha256: "123" }
154
- ]
155
- }
156
- end
157
-
158
- expect(SecureHeaders.header_hash_for(plaintext_request)[PublicKeyPins::HEADER_NAME]).to be_nil
159
- end
160
-
161
134
  context "content security policy" do
162
135
  let(:chrome_request) {
163
136
  Rack::Request.new(request.env.merge("HTTP_USER_AGENT" => USER_AGENTS[:chrome]))
@@ -531,14 +504,6 @@ module SecureHeaders
531
504
  end.to raise_error(ReferrerPolicyConfigError)
532
505
  end
533
506
 
534
- it "validates your hpkp config upon configuration" do
535
- expect do
536
- Configuration.default do |config|
537
- config.hpkp = "lol"
538
- end
539
- end.to raise_error(PublicKeyPinsConfigError)
540
- end
541
-
542
507
  it "validates your cookies config upon configuration" do
543
508
  expect do
544
509
  Configuration.default do |config|
data/spec/spec_helper.rb CHANGED
@@ -37,7 +37,6 @@ def expect_default_values(hash)
37
37
  expect(hash[SecureHeaders::ExpectCertificateTransparency::HEADER_NAME]).to be_nil
38
38
  expect(hash[SecureHeaders::ClearSiteData::HEADER_NAME]).to be_nil
39
39
  expect(hash[SecureHeaders::ExpectCertificateTransparency::HEADER_NAME]).to be_nil
40
- expect(hash[SecureHeaders::PublicKeyPins::HEADER_NAME]).to be_nil
41
40
  end
42
41
 
43
42
  module SecureHeaders
@@ -46,10 +45,20 @@ module SecureHeaders
46
45
  def clear_default_config
47
46
  remove_instance_variable(:@default_config) if defined?(@default_config)
48
47
  end
48
+
49
+ def clear_overrides
50
+ remove_instance_variable(:@overrides) if defined?(@overrides)
51
+ end
52
+
53
+ def clear_appends
54
+ remove_instance_variable(:@appends) if defined?(@appends)
55
+ end
49
56
  end
50
57
  end
51
58
  end
52
59
 
53
60
  def reset_config
54
61
  SecureHeaders::Configuration.clear_default_config
62
+ SecureHeaders::Configuration.clear_overrides
63
+ SecureHeaders::Configuration.clear_appends
55
64
  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: 6.0.0
4
+ version: 6.7.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: 2018-05-08 00:00:00.000000000 Z
11
+ date: 2024-08-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -24,7 +24,10 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
- description: Manages application of security headers with many safe defaults.
27
+ description: |-
28
+ Add easily configured security headers to responses
29
+ including content-security-policy, x-frame-options,
30
+ strict-transport-security, etc.
28
31
  email:
29
32
  - neil.matatall@gmail.com
30
33
  executables: []
@@ -33,12 +36,14 @@ extra_rdoc_files: []
33
36
  files:
34
37
  - ".github/ISSUE_TEMPLATE.md"
35
38
  - ".github/PULL_REQUEST_TEMPLATE.md"
39
+ - ".github/dependabot.yml"
40
+ - ".github/workflows/build.yml"
41
+ - ".github/workflows/github-release.yml"
36
42
  - ".gitignore"
37
43
  - ".rspec"
38
44
  - ".rubocop.yml"
39
45
  - ".ruby-gemset"
40
46
  - ".ruby-version"
41
- - ".travis.yml"
42
47
  - CHANGELOG.md
43
48
  - CODE_OF_CONDUCT.md
44
49
  - CONTRIBUTING.md
@@ -65,7 +70,6 @@ files:
65
70
  - lib/secure_headers/headers/cookie.rb
66
71
  - lib/secure_headers/headers/expect_certificate_transparency.rb
67
72
  - lib/secure_headers/headers/policy_management.rb
68
- - lib/secure_headers/headers/public_key_pins.rb
69
73
  - lib/secure_headers/headers/referrer_policy.rb
70
74
  - lib/secure_headers/headers/strict_transport_security.rb
71
75
  - lib/secure_headers/headers/x_content_type_options.rb
@@ -76,6 +80,7 @@ files:
76
80
  - lib/secure_headers/middleware.rb
77
81
  - lib/secure_headers/railtie.rb
78
82
  - lib/secure_headers/utils/cookies_config.rb
83
+ - lib/secure_headers/version.rb
79
84
  - lib/secure_headers/view_helper.rb
80
85
  - lib/tasks/tasks.rake
81
86
  - secure_headers.gemspec
@@ -85,7 +90,6 @@ files:
85
90
  - spec/lib/secure_headers/headers/cookie_spec.rb
86
91
  - spec/lib/secure_headers/headers/expect_certificate_transparency_spec.rb
87
92
  - spec/lib/secure_headers/headers/policy_management_spec.rb
88
- - spec/lib/secure_headers/headers/public_key_pins_spec.rb
89
93
  - spec/lib/secure_headers/headers/referrer_policy_spec.rb
90
94
  - spec/lib/secure_headers/headers/strict_transport_security_spec.rb
91
95
  - spec/lib/secure_headers/headers/x_content_type_options_spec.rb
@@ -99,7 +103,7 @@ files:
99
103
  - spec/spec_helper.rb
100
104
  homepage: https://github.com/twitter/secureheaders
101
105
  licenses:
102
- - Apache Public License 2.0
106
+ - MIT
103
107
  metadata: {}
104
108
  post_install_message:
105
109
  rdoc_options: []
@@ -116,12 +120,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
116
120
  - !ruby/object:Gem::Version
117
121
  version: '0'
118
122
  requirements: []
119
- rubyforge_project:
120
- rubygems_version: 2.6.13
123
+ rubygems_version: 3.0.3.1
121
124
  signing_key:
122
125
  specification_version: 4
123
- summary: Add easily configured security headers to responses including content-security-policy,
124
- x-frame-options, strict-transport-security, etc.
126
+ summary: Manages application of security headers with many safe defaults.
125
127
  test_files:
126
128
  - spec/lib/secure_headers/configuration_spec.rb
127
129
  - spec/lib/secure_headers/headers/clear_site_data_spec.rb
@@ -129,7 +131,6 @@ test_files:
129
131
  - spec/lib/secure_headers/headers/cookie_spec.rb
130
132
  - spec/lib/secure_headers/headers/expect_certificate_transparency_spec.rb
131
133
  - spec/lib/secure_headers/headers/policy_management_spec.rb
132
- - spec/lib/secure_headers/headers/public_key_pins_spec.rb
133
134
  - spec/lib/secure_headers/headers/referrer_policy_spec.rb
134
135
  - spec/lib/secure_headers/headers/strict_transport_security_spec.rb
135
136
  - spec/lib/secure_headers/headers/x_content_type_options_spec.rb
data/.travis.yml DELETED
@@ -1,29 +0,0 @@
1
- language: ruby
2
-
3
- rvm:
4
- - ruby-head
5
- - 2.5.0
6
- - 2.4.3
7
- - 2.3.6
8
- - 2.2.9
9
- - jruby-head
10
-
11
- env:
12
- - SUITE=rspec spec
13
- - SUITE=rubocop
14
-
15
- script: bundle exec $SUITE
16
-
17
- matrix:
18
- allow_failures:
19
- - rvm: jruby-head
20
- - rvm: ruby-head
21
-
22
- before_install:
23
- - gem update --system
24
- - gem --version
25
- - gem update bundler
26
- bundler_args: --without guard -j 3
27
-
28
- sudo: false
29
- cache: bundler