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