secure_headers 6.0.0 → 6.7.0

Sign up to get free protection for your applications and to get access to all the features.
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