secure_headers 7.0.0 → 7.1.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.
- checksums.yaml +4 -4
- data/README.md +13 -13
- data/lib/secure_headers/configuration.rb +1 -1
- data/lib/secure_headers/headers/clear_site_data.rb +4 -4
- data/lib/secure_headers/headers/content_security_policy.rb +2 -2
- data/lib/secure_headers/headers/content_security_policy_config.rb +2 -2
- data/lib/secure_headers/headers/expect_certificate_transparency.rb +2 -2
- data/lib/secure_headers/headers/policy_management.rb +2 -2
- data/lib/secure_headers/headers/referrer_policy.rb +1 -1
- data/lib/secure_headers/headers/strict_transport_security.rb +1 -1
- data/lib/secure_headers/headers/x_content_type_options.rb +1 -1
- data/lib/secure_headers/headers/x_download_options.rb +2 -2
- data/lib/secure_headers/headers/x_frame_options.rb +1 -1
- data/lib/secure_headers/headers/x_permitted_cross_domain_policies.rb +2 -2
- data/lib/secure_headers/headers/x_xss_protection.rb +1 -1
- data/lib/secure_headers/railtie.rb +5 -5
- data/lib/secure_headers/version.rb +1 -1
- data/secure_headers.gemspec +13 -3
- metadata +14 -63
- data/.github/ISSUE_TEMPLATE.md +0 -41
- data/.github/PULL_REQUEST_TEMPLATE.md +0 -20
- data/.github/dependabot.yml +0 -6
- data/.github/workflows/build.yml +0 -25
- data/.github/workflows/github-release.yml +0 -28
- data/.gitignore +0 -13
- data/.rspec +0 -3
- data/.rubocop.yml +0 -4
- data/.ruby-gemset +0 -1
- data/.ruby-version +0 -1
- data/CODE_OF_CONDUCT.md +0 -46
- data/CONTRIBUTING.md +0 -41
- data/Guardfile +0 -13
- data/Rakefile +0 -32
- data/docs/cookies.md +0 -65
- data/docs/hashes.md +0 -64
- data/docs/named_overrides_and_appends.md +0 -104
- data/docs/per_action_configuration.md +0 -139
- data/docs/sinatra.md +0 -25
- data/docs/upgrading-to-3-0.md +0 -42
- data/docs/upgrading-to-4-0.md +0 -35
- data/docs/upgrading-to-5-0.md +0 -15
- data/docs/upgrading-to-6-0.md +0 -50
- data/docs/upgrading-to-7-0.md +0 -12
- data/spec/lib/secure_headers/configuration_spec.rb +0 -121
- data/spec/lib/secure_headers/headers/clear_site_data_spec.rb +0 -87
- data/spec/lib/secure_headers/headers/content_security_policy_spec.rb +0 -215
- data/spec/lib/secure_headers/headers/cookie_spec.rb +0 -179
- data/spec/lib/secure_headers/headers/expect_certificate_transparency_spec.rb +0 -42
- data/spec/lib/secure_headers/headers/policy_management_spec.rb +0 -265
- data/spec/lib/secure_headers/headers/referrer_policy_spec.rb +0 -91
- data/spec/lib/secure_headers/headers/strict_transport_security_spec.rb +0 -33
- data/spec/lib/secure_headers/headers/x_content_type_options_spec.rb +0 -31
- data/spec/lib/secure_headers/headers/x_download_options_spec.rb +0 -29
- data/spec/lib/secure_headers/headers/x_frame_options_spec.rb +0 -36
- data/spec/lib/secure_headers/headers/x_permitted_cross_domain_policies_spec.rb +0 -48
- data/spec/lib/secure_headers/headers/x_xss_protection_spec.rb +0 -47
- data/spec/lib/secure_headers/middleware_spec.rb +0 -117
- data/spec/lib/secure_headers/view_helpers_spec.rb +0 -192
- data/spec/lib/secure_headers_spec.rb +0 -516
- data/spec/spec_helper.rb +0 -64
@@ -1,516 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require "spec_helper"
|
3
|
-
|
4
|
-
module SecureHeaders
|
5
|
-
describe SecureHeaders do
|
6
|
-
before(:each) do
|
7
|
-
reset_config
|
8
|
-
end
|
9
|
-
|
10
|
-
let(:request) { Rack::Request.new("HTTP_X_FORWARDED_SSL" => "on") }
|
11
|
-
|
12
|
-
it "raises a NotYetConfiguredError if default has not been set" do
|
13
|
-
expect do
|
14
|
-
SecureHeaders.header_hash_for(request)
|
15
|
-
end.to raise_error(Configuration::NotYetConfiguredError)
|
16
|
-
end
|
17
|
-
|
18
|
-
it "raises a NotYetConfiguredError if trying to opt-out of unconfigured headers" do
|
19
|
-
expect do
|
20
|
-
SecureHeaders.opt_out_of_header(request, :csp)
|
21
|
-
end.to raise_error(Configuration::NotYetConfiguredError)
|
22
|
-
end
|
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
|
-
|
31
|
-
it "raises and ArgumentError when referencing an override that has not been set" do
|
32
|
-
expect do
|
33
|
-
Configuration.default
|
34
|
-
SecureHeaders.use_secure_headers_override(request, :missing)
|
35
|
-
end.to raise_error(ArgumentError)
|
36
|
-
end
|
37
|
-
|
38
|
-
describe "#header_hash_for" do
|
39
|
-
it "allows you to opt out of individual headers via API" do
|
40
|
-
Configuration.default do |config|
|
41
|
-
config.csp = { default_src: %w('self'), script_src: %w('self')}
|
42
|
-
config.csp_report_only = config.csp
|
43
|
-
end
|
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)
|
47
|
-
hash = SecureHeaders.header_hash_for(request)
|
48
|
-
expect(hash["Content-Security-Policy-Report-Only"]).to be_nil
|
49
|
-
expect(hash["Content-Security-Policy"]).to be_nil
|
50
|
-
expect(hash["X-Content-Type-Options"]).to be_nil
|
51
|
-
end
|
52
|
-
|
53
|
-
it "Carries options over when using overrides" do
|
54
|
-
Configuration.default do |config|
|
55
|
-
config.x_download_options = OPT_OUT
|
56
|
-
config.x_permitted_cross_domain_policies = OPT_OUT
|
57
|
-
end
|
58
|
-
|
59
|
-
Configuration.override(:api) do |config|
|
60
|
-
config.x_frame_options = OPT_OUT
|
61
|
-
end
|
62
|
-
|
63
|
-
SecureHeaders.use_secure_headers_override(request, :api)
|
64
|
-
hash = SecureHeaders.header_hash_for(request)
|
65
|
-
expect(hash["X-Download-Options"]).to be_nil
|
66
|
-
expect(hash["X-Permitted-Cross-Domain-Policies"]).to be_nil
|
67
|
-
expect(hash["X-Frame-Options"]).to be_nil
|
68
|
-
end
|
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
|
-
|
88
|
-
it "allows you to opt out entirely" do
|
89
|
-
# configure the disabled-by-default headers to ensure they also do not get set
|
90
|
-
Configuration.default do |config|
|
91
|
-
config.csp = { default_src: ["example.com"], script_src: %w('self') }
|
92
|
-
config.csp_report_only = config.csp
|
93
|
-
end
|
94
|
-
SecureHeaders.opt_out_of_all_protection(request)
|
95
|
-
hash = SecureHeaders.header_hash_for(request)
|
96
|
-
expect(hash.count).to eq(0)
|
97
|
-
end
|
98
|
-
|
99
|
-
it "allows you to override X-Frame-Options settings" do
|
100
|
-
Configuration.default
|
101
|
-
SecureHeaders.override_x_frame_options(request, XFrameOptions::DENY)
|
102
|
-
hash = SecureHeaders.header_hash_for(request)
|
103
|
-
expect(hash[XFrameOptions::HEADER_NAME]).to eq(XFrameOptions::DENY)
|
104
|
-
end
|
105
|
-
|
106
|
-
it "allows you to override opting out" do
|
107
|
-
Configuration.default do |config|
|
108
|
-
config.x_frame_options = OPT_OUT
|
109
|
-
config.csp = OPT_OUT
|
110
|
-
end
|
111
|
-
|
112
|
-
SecureHeaders.override_x_frame_options(request, XFrameOptions::SAMEORIGIN)
|
113
|
-
SecureHeaders.override_content_security_policy_directives(request, default_src: %w(https:), script_src: %w('self'))
|
114
|
-
|
115
|
-
hash = SecureHeaders.header_hash_for(request)
|
116
|
-
expect(hash[ContentSecurityPolicyConfig::HEADER_NAME]).to eq("default-src https:; script-src 'self'")
|
117
|
-
expect(hash[XFrameOptions::HEADER_NAME]).to eq(XFrameOptions::SAMEORIGIN)
|
118
|
-
end
|
119
|
-
|
120
|
-
it "produces a hash of headers with default config" do
|
121
|
-
Configuration.default
|
122
|
-
hash = SecureHeaders.header_hash_for(request)
|
123
|
-
expect_default_values(hash)
|
124
|
-
end
|
125
|
-
|
126
|
-
it "does not set the HSTS header if request is over HTTP" do
|
127
|
-
plaintext_request = Rack::Request.new({})
|
128
|
-
Configuration.default do |config|
|
129
|
-
config.hsts = "max-age=123456"
|
130
|
-
end
|
131
|
-
expect(SecureHeaders.header_hash_for(plaintext_request)[StrictTransportSecurity::HEADER_NAME]).to be_nil
|
132
|
-
end
|
133
|
-
|
134
|
-
context "content security policy" do
|
135
|
-
let(:chrome_request) {
|
136
|
-
Rack::Request.new(request.env.merge("HTTP_USER_AGENT" => USER_AGENTS[:chrome]))
|
137
|
-
}
|
138
|
-
|
139
|
-
it "appends a value to csp directive" do
|
140
|
-
Configuration.default do |config|
|
141
|
-
config.csp = {
|
142
|
-
default_src: %w('self'),
|
143
|
-
script_src: %w(mycdn.com 'unsafe-inline')
|
144
|
-
}
|
145
|
-
end
|
146
|
-
|
147
|
-
SecureHeaders.append_content_security_policy_directives(request, script_src: %w(anothercdn.com))
|
148
|
-
hash = SecureHeaders.header_hash_for(request)
|
149
|
-
expect(hash[ContentSecurityPolicyConfig::HEADER_NAME]).to eq("default-src 'self'; script-src mycdn.com 'unsafe-inline' anothercdn.com")
|
150
|
-
end
|
151
|
-
|
152
|
-
it "supports named appends" do
|
153
|
-
Configuration.default do |config|
|
154
|
-
config.csp = {
|
155
|
-
default_src: %w('self'),
|
156
|
-
script_src: %w('self')
|
157
|
-
}
|
158
|
-
end
|
159
|
-
|
160
|
-
Configuration.named_append(:moar_default_sources) do |request|
|
161
|
-
{ default_src: %w(https:), style_src: %w('self')}
|
162
|
-
end
|
163
|
-
|
164
|
-
Configuration.named_append(:how_about_a_script_src_too) do |request|
|
165
|
-
{ script_src: %w('unsafe-inline')}
|
166
|
-
end
|
167
|
-
|
168
|
-
SecureHeaders.use_content_security_policy_named_append(request, :moar_default_sources)
|
169
|
-
SecureHeaders.use_content_security_policy_named_append(request, :how_about_a_script_src_too)
|
170
|
-
hash = SecureHeaders.header_hash_for(request)
|
171
|
-
|
172
|
-
expect(hash[ContentSecurityPolicyConfig::HEADER_NAME]).to eq("default-src 'self' https:; script-src 'self' 'unsafe-inline'; style-src 'self'")
|
173
|
-
end
|
174
|
-
|
175
|
-
it "appends a nonce to a missing script-src value" do
|
176
|
-
Configuration.default do |config|
|
177
|
-
config.csp = {
|
178
|
-
default_src: %w('self'),
|
179
|
-
script_src: %w('self')
|
180
|
-
}
|
181
|
-
end
|
182
|
-
|
183
|
-
SecureHeaders.content_security_policy_script_nonce(request) # should add the value to the header
|
184
|
-
hash = SecureHeaders.header_hash_for(chrome_request)
|
185
|
-
expect(hash[ContentSecurityPolicyConfig::HEADER_NAME]).to match(/\Adefault-src 'self'; script-src 'self' 'nonce-.*'\z/)
|
186
|
-
end
|
187
|
-
|
188
|
-
it "appends a hash to a missing script-src value" do
|
189
|
-
Configuration.default do |config|
|
190
|
-
config.csp = {
|
191
|
-
default_src: %w('self'),
|
192
|
-
script_src: %w('self')
|
193
|
-
}
|
194
|
-
end
|
195
|
-
|
196
|
-
SecureHeaders.append_content_security_policy_directives(request, script_src: %w('sha256-abc123'))
|
197
|
-
hash = SecureHeaders.header_hash_for(chrome_request)
|
198
|
-
expect(hash[ContentSecurityPolicyConfig::HEADER_NAME]).to match(/\Adefault-src 'self'; script-src 'self' 'sha256-abc123'\z/)
|
199
|
-
end
|
200
|
-
|
201
|
-
it "overrides individual directives" do
|
202
|
-
Configuration.default do |config|
|
203
|
-
config.csp = {
|
204
|
-
default_src: %w('self'),
|
205
|
-
script_src: %w('self')
|
206
|
-
}
|
207
|
-
end
|
208
|
-
SecureHeaders.override_content_security_policy_directives(request, default_src: %w('none'))
|
209
|
-
hash = SecureHeaders.header_hash_for(request)
|
210
|
-
expect(hash[ContentSecurityPolicyConfig::HEADER_NAME]).to eq("default-src 'none'; script-src 'self'")
|
211
|
-
end
|
212
|
-
|
213
|
-
it "overrides non-existant directives" do
|
214
|
-
Configuration.default do |config|
|
215
|
-
config.csp = {
|
216
|
-
default_src: %w(https:),
|
217
|
-
script_src: %w('self')
|
218
|
-
}
|
219
|
-
end
|
220
|
-
SecureHeaders.override_content_security_policy_directives(request, img_src: [ContentSecurityPolicy::DATA_PROTOCOL])
|
221
|
-
hash = SecureHeaders.header_hash_for(request)
|
222
|
-
expect(hash[ContentSecurityPolicyReportOnlyConfig::HEADER_NAME]).to be_nil
|
223
|
-
expect(hash[ContentSecurityPolicyConfig::HEADER_NAME]).to eq("default-src https:; img-src data:; script-src 'self'")
|
224
|
-
end
|
225
|
-
|
226
|
-
it "appends a nonce to the script-src when used" do
|
227
|
-
Configuration.default do |config|
|
228
|
-
config.csp = {
|
229
|
-
default_src: %w('self'),
|
230
|
-
script_src: %w(mycdn.com),
|
231
|
-
style_src: %w('self')
|
232
|
-
}
|
233
|
-
end
|
234
|
-
|
235
|
-
nonce = SecureHeaders.content_security_policy_script_nonce(chrome_request)
|
236
|
-
|
237
|
-
# simulate the nonce being used multiple times in a request:
|
238
|
-
SecureHeaders.content_security_policy_script_nonce(chrome_request)
|
239
|
-
SecureHeaders.content_security_policy_script_nonce(chrome_request)
|
240
|
-
SecureHeaders.content_security_policy_script_nonce(chrome_request)
|
241
|
-
|
242
|
-
hash = SecureHeaders.header_hash_for(chrome_request)
|
243
|
-
expect(hash["Content-Security-Policy"]).to eq("default-src 'self'; script-src mycdn.com 'nonce-#{nonce}' 'unsafe-inline'; style-src 'self'")
|
244
|
-
end
|
245
|
-
|
246
|
-
it "does not support the deprecated `report_only: true` format" do
|
247
|
-
expect {
|
248
|
-
Configuration.default do |config|
|
249
|
-
config.csp = {
|
250
|
-
default_src: %w('self'),
|
251
|
-
report_only: true
|
252
|
-
}
|
253
|
-
end
|
254
|
-
}.to raise_error(ContentSecurityPolicyConfigError)
|
255
|
-
end
|
256
|
-
|
257
|
-
it "Raises an error if csp_report_only is used with `report_only: false`" do
|
258
|
-
expect do
|
259
|
-
Configuration.default do |config|
|
260
|
-
config.csp_report_only = {
|
261
|
-
default_src: %w('self'),
|
262
|
-
script_src: %w('self'),
|
263
|
-
report_only: false
|
264
|
-
}
|
265
|
-
end
|
266
|
-
end.to raise_error(ContentSecurityPolicyConfigError)
|
267
|
-
end
|
268
|
-
|
269
|
-
context "setting two headers" do
|
270
|
-
before(:each) do
|
271
|
-
Configuration.default do |config|
|
272
|
-
config.csp = {
|
273
|
-
default_src: %w('self'),
|
274
|
-
script_src: %w('self')
|
275
|
-
}
|
276
|
-
config.csp_report_only = config.csp
|
277
|
-
end
|
278
|
-
end
|
279
|
-
|
280
|
-
it "sets identical values when the configs are the same" do
|
281
|
-
reset_config
|
282
|
-
Configuration.default do |config|
|
283
|
-
config.csp = {
|
284
|
-
default_src: %w('self'),
|
285
|
-
script_src: %w('self')
|
286
|
-
}
|
287
|
-
config.csp_report_only = {
|
288
|
-
default_src: %w('self'),
|
289
|
-
script_src: %w('self')
|
290
|
-
}
|
291
|
-
end
|
292
|
-
|
293
|
-
hash = SecureHeaders.header_hash_for(request)
|
294
|
-
expect(hash["Content-Security-Policy"]).to eq("default-src 'self'; script-src 'self'")
|
295
|
-
expect(hash["Content-Security-Policy-Report-Only"]).to eq("default-src 'self'; script-src 'self'")
|
296
|
-
end
|
297
|
-
|
298
|
-
it "sets different headers when the configs are different" do
|
299
|
-
reset_config
|
300
|
-
Configuration.default do |config|
|
301
|
-
config.csp = {
|
302
|
-
default_src: %w('self'),
|
303
|
-
script_src: %w('self')
|
304
|
-
}
|
305
|
-
config.csp_report_only = config.csp.merge({script_src: %w(foo.com)})
|
306
|
-
end
|
307
|
-
|
308
|
-
hash = SecureHeaders.header_hash_for(request)
|
309
|
-
expect(hash["Content-Security-Policy"]).to eq("default-src 'self'; script-src 'self'")
|
310
|
-
expect(hash["Content-Security-Policy-Report-Only"]).to eq("default-src 'self'; script-src foo.com")
|
311
|
-
end
|
312
|
-
|
313
|
-
it "allows you to opt-out of enforced CSP" do
|
314
|
-
reset_config
|
315
|
-
Configuration.default do |config|
|
316
|
-
config.csp = SecureHeaders::OPT_OUT
|
317
|
-
config.csp_report_only = {
|
318
|
-
default_src: %w('self'),
|
319
|
-
script_src: %w('self')
|
320
|
-
}
|
321
|
-
end
|
322
|
-
|
323
|
-
hash = SecureHeaders.header_hash_for(request)
|
324
|
-
expect(hash["Content-Security-Policy"]).to be_nil
|
325
|
-
expect(hash["Content-Security-Policy-Report-Only"]).to eq("default-src 'self'; script-src 'self'")
|
326
|
-
end
|
327
|
-
|
328
|
-
it "allows appending to the enforced policy" do
|
329
|
-
SecureHeaders.append_content_security_policy_directives(request, {script_src: %w(anothercdn.com)}, :enforced)
|
330
|
-
hash = SecureHeaders.header_hash_for(request)
|
331
|
-
expect(hash["Content-Security-Policy"]).to eq("default-src 'self'; script-src 'self' anothercdn.com")
|
332
|
-
expect(hash["Content-Security-Policy-Report-Only"]).to eq("default-src 'self'; script-src 'self'")
|
333
|
-
end
|
334
|
-
|
335
|
-
it "allows appending to the report only policy" do
|
336
|
-
SecureHeaders.append_content_security_policy_directives(request, {script_src: %w(anothercdn.com)}, :report_only)
|
337
|
-
hash = SecureHeaders.header_hash_for(request)
|
338
|
-
expect(hash["Content-Security-Policy"]).to eq("default-src 'self'; script-src 'self'")
|
339
|
-
expect(hash["Content-Security-Policy-Report-Only"]).to eq("default-src 'self'; script-src 'self' anothercdn.com")
|
340
|
-
end
|
341
|
-
|
342
|
-
it "allows appending to both policies" do
|
343
|
-
SecureHeaders.append_content_security_policy_directives(request, {script_src: %w(anothercdn.com)}, :both)
|
344
|
-
hash = SecureHeaders.header_hash_for(request)
|
345
|
-
expect(hash["Content-Security-Policy"]).to eq("default-src 'self'; script-src 'self' anothercdn.com")
|
346
|
-
expect(hash["Content-Security-Policy-Report-Only"]).to eq("default-src 'self'; script-src 'self' anothercdn.com")
|
347
|
-
end
|
348
|
-
|
349
|
-
it "allows overriding the enforced policy" do
|
350
|
-
SecureHeaders.override_content_security_policy_directives(request, {script_src: %w(anothercdn.com)}, :enforced)
|
351
|
-
hash = SecureHeaders.header_hash_for(request)
|
352
|
-
expect(hash["Content-Security-Policy"]).to eq("default-src 'self'; script-src anothercdn.com")
|
353
|
-
expect(hash["Content-Security-Policy-Report-Only"]).to eq("default-src 'self'; script-src 'self'")
|
354
|
-
end
|
355
|
-
|
356
|
-
it "allows overriding the report only policy" do
|
357
|
-
SecureHeaders.override_content_security_policy_directives(request, {script_src: %w(anothercdn.com)}, :report_only)
|
358
|
-
hash = SecureHeaders.header_hash_for(request)
|
359
|
-
expect(hash["Content-Security-Policy"]).to eq("default-src 'self'; script-src 'self'")
|
360
|
-
expect(hash["Content-Security-Policy-Report-Only"]).to eq("default-src 'self'; script-src anothercdn.com")
|
361
|
-
end
|
362
|
-
|
363
|
-
it "allows overriding both policies" do
|
364
|
-
SecureHeaders.override_content_security_policy_directives(request, {script_src: %w(anothercdn.com)}, :both)
|
365
|
-
hash = SecureHeaders.header_hash_for(request)
|
366
|
-
expect(hash["Content-Security-Policy"]).to eq("default-src 'self'; script-src anothercdn.com")
|
367
|
-
expect(hash["Content-Security-Policy-Report-Only"]).to eq("default-src 'self'; script-src anothercdn.com")
|
368
|
-
end
|
369
|
-
|
370
|
-
context "when inferring which config to modify" do
|
371
|
-
it "updates the enforced header when configured" do
|
372
|
-
reset_config
|
373
|
-
Configuration.default do |config|
|
374
|
-
config.csp = {
|
375
|
-
default_src: %w('self'),
|
376
|
-
script_src: %w('self')
|
377
|
-
}
|
378
|
-
end
|
379
|
-
SecureHeaders.append_content_security_policy_directives(request, {script_src: %w(anothercdn.com)})
|
380
|
-
|
381
|
-
hash = SecureHeaders.header_hash_for(request)
|
382
|
-
expect(hash["Content-Security-Policy"]).to eq("default-src 'self'; script-src 'self' anothercdn.com")
|
383
|
-
expect(hash["Content-Security-Policy-Report-Only"]).to be_nil
|
384
|
-
end
|
385
|
-
|
386
|
-
it "updates the report only header when configured" do
|
387
|
-
reset_config
|
388
|
-
Configuration.default do |config|
|
389
|
-
config.csp = OPT_OUT
|
390
|
-
config.csp_report_only = {
|
391
|
-
default_src: %w('self'),
|
392
|
-
script_src: %w('self')
|
393
|
-
}
|
394
|
-
end
|
395
|
-
SecureHeaders.append_content_security_policy_directives(request, {script_src: %w(anothercdn.com)})
|
396
|
-
|
397
|
-
hash = SecureHeaders.header_hash_for(request)
|
398
|
-
expect(hash["Content-Security-Policy-Report-Only"]).to eq("default-src 'self'; script-src 'self' anothercdn.com")
|
399
|
-
expect(hash["Content-Security-Policy"]).to be_nil
|
400
|
-
end
|
401
|
-
|
402
|
-
it "updates both headers if both are configured" do
|
403
|
-
reset_config
|
404
|
-
Configuration.default do |config|
|
405
|
-
config.csp = {
|
406
|
-
default_src: %w(enforced.com),
|
407
|
-
script_src: %w('self')
|
408
|
-
}
|
409
|
-
config.csp_report_only = {
|
410
|
-
default_src: %w(reportonly.com),
|
411
|
-
script_src: %w('self')
|
412
|
-
}
|
413
|
-
end
|
414
|
-
SecureHeaders.append_content_security_policy_directives(request, {script_src: %w(anothercdn.com)})
|
415
|
-
|
416
|
-
hash = SecureHeaders.header_hash_for(request)
|
417
|
-
expect(hash["Content-Security-Policy"]).to eq("default-src enforced.com; script-src 'self' anothercdn.com")
|
418
|
-
expect(hash["Content-Security-Policy-Report-Only"]).to eq("default-src reportonly.com; script-src 'self' anothercdn.com")
|
419
|
-
end
|
420
|
-
|
421
|
-
end
|
422
|
-
end
|
423
|
-
end
|
424
|
-
end
|
425
|
-
|
426
|
-
context "validation" do
|
427
|
-
it "validates your hsts config upon configuration" do
|
428
|
-
expect do
|
429
|
-
Configuration.default do |config|
|
430
|
-
config.hsts = "lol"
|
431
|
-
end
|
432
|
-
end.to raise_error(STSConfigError)
|
433
|
-
end
|
434
|
-
|
435
|
-
it "validates your csp config upon configuration" do
|
436
|
-
expect do
|
437
|
-
Configuration.default do |config|
|
438
|
-
config.csp = { ContentSecurityPolicy::DEFAULT_SRC => "123456" }
|
439
|
-
end
|
440
|
-
end.to raise_error(ContentSecurityPolicyConfigError)
|
441
|
-
end
|
442
|
-
|
443
|
-
it "raises errors for unknown directives" do
|
444
|
-
expect do
|
445
|
-
Configuration.default do |config|
|
446
|
-
config.csp = { made_up_directive: "123456" }
|
447
|
-
end
|
448
|
-
end.to raise_error(ContentSecurityPolicyConfigError)
|
449
|
-
end
|
450
|
-
|
451
|
-
it "validates your xfo config upon configuration" do
|
452
|
-
expect do
|
453
|
-
Configuration.default do |config|
|
454
|
-
config.x_frame_options = "NOPE"
|
455
|
-
end
|
456
|
-
end.to raise_error(XFOConfigError)
|
457
|
-
end
|
458
|
-
|
459
|
-
it "validates your xcto config upon configuration" do
|
460
|
-
expect do
|
461
|
-
Configuration.default do |config|
|
462
|
-
config.x_content_type_options = "lol"
|
463
|
-
end
|
464
|
-
end.to raise_error(XContentTypeOptionsConfigError)
|
465
|
-
end
|
466
|
-
|
467
|
-
it "validates your clear site data config upon configuration" do
|
468
|
-
expect do
|
469
|
-
Configuration.default do |config|
|
470
|
-
config.clear_site_data = 1
|
471
|
-
end
|
472
|
-
end.to raise_error(ClearSiteDataConfigError)
|
473
|
-
end
|
474
|
-
|
475
|
-
it "validates your x_xss config upon configuration" do
|
476
|
-
expect do
|
477
|
-
Configuration.default do |config|
|
478
|
-
config.x_xss_protection = "lol"
|
479
|
-
end
|
480
|
-
end.to raise_error(XXssProtectionConfigError)
|
481
|
-
end
|
482
|
-
|
483
|
-
it "validates your xdo config upon configuration" do
|
484
|
-
expect do
|
485
|
-
Configuration.default do |config|
|
486
|
-
config.x_download_options = "lol"
|
487
|
-
end
|
488
|
-
end.to raise_error(XDOConfigError)
|
489
|
-
end
|
490
|
-
|
491
|
-
it "validates your x_permitted_cross_domain_policies config upon configuration" do
|
492
|
-
expect do
|
493
|
-
Configuration.default do |config|
|
494
|
-
config.x_permitted_cross_domain_policies = "lol"
|
495
|
-
end
|
496
|
-
end.to raise_error(XPCDPConfigError)
|
497
|
-
end
|
498
|
-
|
499
|
-
it "validates your referrer_policy config upon configuration" do
|
500
|
-
expect do
|
501
|
-
Configuration.default do |config|
|
502
|
-
config.referrer_policy = "lol"
|
503
|
-
end
|
504
|
-
end.to raise_error(ReferrerPolicyConfigError)
|
505
|
-
end
|
506
|
-
|
507
|
-
it "validates your cookies config upon configuration" do
|
508
|
-
expect do
|
509
|
-
Configuration.default do |config|
|
510
|
-
config.cookies = { secure: "lol" }
|
511
|
-
end
|
512
|
-
end.to raise_error(CookiesConfigError)
|
513
|
-
end
|
514
|
-
end
|
515
|
-
end
|
516
|
-
end
|
data/spec/spec_helper.rb
DELETED
@@ -1,64 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require "rubygems"
|
3
|
-
require "rspec"
|
4
|
-
require "rack"
|
5
|
-
require "coveralls"
|
6
|
-
Coveralls.wear!
|
7
|
-
|
8
|
-
require File.join(File.dirname(__FILE__), "..", "lib", "secure_headers")
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
USER_AGENTS = {
|
13
|
-
edge: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.246",
|
14
|
-
firefox: "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:14.0) Gecko/20100101 Firefox/14.0.1",
|
15
|
-
firefox46: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:46.0) Gecko/20100101 Firefox/46.0",
|
16
|
-
chrome: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.56 Safari/536.5",
|
17
|
-
ie: "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/5.0)",
|
18
|
-
opera: "Opera/9.80 (Windows NT 6.1; U; es-ES) Presto/2.9.181 Version/12.00",
|
19
|
-
ios5: "Mozilla/5.0 (iPhone; CPU iPhone OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3",
|
20
|
-
ios6: "Mozilla/5.0 (iPhone; CPU iPhone OS 614 like Mac OS X) AppleWebKit/536.26 (KHTML like Gecko) Version/6.0 Mobile/10B350 Safari/8536.25",
|
21
|
-
safari5: "Mozilla/5.0 (iPad; CPU OS 5_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko ) Version/5.1 Mobile/9B176 Safari/7534.48.3",
|
22
|
-
safari5_1: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/534.55.3 (KHTML, like Gecko) Version/5.1.3 Safari/534.53.10",
|
23
|
-
safari6: "Mozilla/5.0 (Macintosh; Intel Mac OS X 1084) AppleWebKit/536.30.1 (KHTML like Gecko) Version/6.0.5 Safari/536.30.1",
|
24
|
-
safari10: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/602.2.11 (KHTML, like Gecko) Version/10.0.1 Safari/602.2.11"
|
25
|
-
}
|
26
|
-
|
27
|
-
def expect_default_values(hash)
|
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
|
30
|
-
expect(hash[SecureHeaders::XFrameOptions::HEADER_NAME]).to eq(SecureHeaders::XFrameOptions::DEFAULT_VALUE)
|
31
|
-
expect(hash[SecureHeaders::XDownloadOptions::HEADER_NAME]).to eq(SecureHeaders::XDownloadOptions::DEFAULT_VALUE)
|
32
|
-
expect(hash[SecureHeaders::StrictTransportSecurity::HEADER_NAME]).to eq(SecureHeaders::StrictTransportSecurity::DEFAULT_VALUE)
|
33
|
-
expect(hash[SecureHeaders::XXssProtection::HEADER_NAME]).to eq(SecureHeaders::XXssProtection::DEFAULT_VALUE)
|
34
|
-
expect(hash[SecureHeaders::XContentTypeOptions::HEADER_NAME]).to eq(SecureHeaders::XContentTypeOptions::DEFAULT_VALUE)
|
35
|
-
expect(hash[SecureHeaders::XPermittedCrossDomainPolicies::HEADER_NAME]).to eq(SecureHeaders::XPermittedCrossDomainPolicies::DEFAULT_VALUE)
|
36
|
-
expect(hash[SecureHeaders::ReferrerPolicy::HEADER_NAME]).to be_nil
|
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
|
-
end
|
41
|
-
|
42
|
-
module SecureHeaders
|
43
|
-
class Configuration
|
44
|
-
class << self
|
45
|
-
def clear_default_config
|
46
|
-
remove_instance_variable(:@default_config) if defined?(@default_config)
|
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
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def reset_config
|
61
|
-
SecureHeaders::Configuration.clear_default_config
|
62
|
-
SecureHeaders::Configuration.clear_overrides
|
63
|
-
SecureHeaders::Configuration.clear_appends
|
64
|
-
end
|