secure_headers 3.9.0 → 4.0.2
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 +5 -5
- data/.rspec +1 -0
- data/.rubocop.yml +3 -0
- data/.ruby-version +1 -1
- data/.travis.yml +8 -6
- data/CHANGELOG.md +6 -14
- data/CONTRIBUTING.md +1 -1
- data/Gemfile +7 -4
- data/Guardfile +1 -0
- data/README.md +8 -40
- data/Rakefile +22 -18
- data/docs/cookies.md +18 -5
- data/docs/per_action_configuration.md +28 -0
- data/lib/secure_headers/configuration.rb +5 -12
- data/lib/secure_headers/hash_helper.rb +2 -1
- data/lib/secure_headers/headers/clear_site_data.rb +4 -3
- data/lib/secure_headers/headers/content_security_policy.rb +10 -19
- data/lib/secure_headers/headers/content_security_policy_config.rb +1 -0
- data/lib/secure_headers/headers/cookie.rb +22 -10
- data/lib/secure_headers/headers/expect_certificate_transparency.rb +1 -1
- data/lib/secure_headers/headers/policy_management.rb +14 -2
- data/lib/secure_headers/headers/public_key_pins.rb +4 -3
- data/lib/secure_headers/headers/referrer_policy.rb +1 -0
- data/lib/secure_headers/headers/strict_transport_security.rb +2 -1
- data/lib/secure_headers/headers/x_content_type_options.rb +1 -0
- data/lib/secure_headers/headers/x_download_options.rb +2 -1
- data/lib/secure_headers/headers/x_frame_options.rb +1 -0
- data/lib/secure_headers/headers/x_permitted_cross_domain_policies.rb +2 -1
- data/lib/secure_headers/headers/x_xss_protection.rb +2 -1
- data/lib/secure_headers/middleware.rb +10 -9
- data/lib/secure_headers/railtie.rb +7 -6
- data/lib/secure_headers/utils/cookies_config.rb +17 -18
- data/lib/secure_headers/view_helper.rb +2 -1
- data/lib/secure_headers.rb +2 -1
- data/lib/tasks/tasks.rake +2 -1
- data/secure_headers.gemspec +13 -3
- data/spec/lib/secure_headers/configuration_spec.rb +9 -8
- data/spec/lib/secure_headers/headers/clear_site_data_spec.rb +2 -1
- data/spec/lib/secure_headers/headers/content_security_policy_spec.rb +13 -27
- data/spec/lib/secure_headers/headers/cookie_spec.rb +58 -37
- data/spec/lib/secure_headers/headers/policy_management_spec.rb +26 -10
- data/spec/lib/secure_headers/headers/public_key_pins_spec.rb +7 -6
- data/spec/lib/secure_headers/headers/referrer_policy_spec.rb +4 -3
- data/spec/lib/secure_headers/headers/strict_transport_security_spec.rb +5 -4
- data/spec/lib/secure_headers/headers/x_content_type_options_spec.rb +2 -1
- data/spec/lib/secure_headers/headers/x_download_options_spec.rb +3 -2
- data/spec/lib/secure_headers/headers/x_frame_options_spec.rb +2 -1
- data/spec/lib/secure_headers/headers/x_permitted_cross_domain_policies_spec.rb +4 -3
- data/spec/lib/secure_headers/headers/x_xss_protection_spec.rb +4 -3
- data/spec/lib/secure_headers/middleware_spec.rb +29 -21
- data/spec/lib/secure_headers/view_helpers_spec.rb +5 -4
- data/spec/lib/secure_headers_spec.rb +92 -120
- data/spec/spec_helper.rb +9 -22
- data/upgrading-to-4-0.md +55 -0
- metadata +14 -6
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require "spec_helper"
|
|
2
3
|
|
|
3
4
|
module SecureHeaders
|
|
4
5
|
describe PolicyManagement do
|
|
@@ -16,7 +17,7 @@ module SecureHeaders
|
|
|
16
17
|
it "accepts all keys" do
|
|
17
18
|
# (pulled from README)
|
|
18
19
|
config = {
|
|
19
|
-
# "meta" values. these will
|
|
20
|
+
# "meta" values. these will shape the header, but the values are not included in the header.
|
|
20
21
|
report_only: true, # default: false
|
|
21
22
|
preserve_schemes: true, # default: false. Schemes are removed from host sources to save bytes and discourage mixed content.
|
|
22
23
|
|
|
@@ -47,10 +48,22 @@ module SecureHeaders
|
|
|
47
48
|
|
|
48
49
|
it "requires a :default_src value" do
|
|
49
50
|
expect do
|
|
50
|
-
ContentSecurityPolicy.validate_config!(ContentSecurityPolicyConfig.new(script_src: %('self')))
|
|
51
|
+
ContentSecurityPolicy.validate_config!(ContentSecurityPolicyConfig.new(script_src: %w('self')))
|
|
51
52
|
end.to raise_error(ContentSecurityPolicyConfigError)
|
|
52
53
|
end
|
|
53
54
|
|
|
55
|
+
it "requires a :script_src value" do
|
|
56
|
+
expect do
|
|
57
|
+
ContentSecurityPolicy.validate_config!(ContentSecurityPolicyConfig.new(default_src: %w('self')))
|
|
58
|
+
end.to raise_error(ContentSecurityPolicyConfigError)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it "accepts OPT_OUT as a script-src value" do
|
|
62
|
+
expect do
|
|
63
|
+
ContentSecurityPolicy.validate_config!(ContentSecurityPolicyConfig.new(default_src: %w('self'), script_src: OPT_OUT))
|
|
64
|
+
end.to_not raise_error
|
|
65
|
+
end
|
|
66
|
+
|
|
54
67
|
it "requires :report_only to be a truthy value" do
|
|
55
68
|
expect do
|
|
56
69
|
ContentSecurityPolicy.validate_config!(ContentSecurityPolicyConfig.new(default_opts.merge(report_only: "steve")))
|
|
@@ -96,7 +109,7 @@ module SecureHeaders
|
|
|
96
109
|
# this is mostly to ensure people don't use the antiquated shorthands common in other configs
|
|
97
110
|
it "performs light validation on source lists" do
|
|
98
111
|
expect do
|
|
99
|
-
ContentSecurityPolicy.validate_config!(ContentSecurityPolicyConfig.new(default_src: %w(self none inline eval)))
|
|
112
|
+
ContentSecurityPolicy.validate_config!(ContentSecurityPolicyConfig.new(default_src: %w(self none inline eval), script_src: %w('self')))
|
|
100
113
|
end.to raise_error(ContentSecurityPolicyConfigError)
|
|
101
114
|
end
|
|
102
115
|
|
|
@@ -135,19 +148,21 @@ module SecureHeaders
|
|
|
135
148
|
it "combines the default-src value with the override if the directive was unconfigured" do
|
|
136
149
|
Configuration.default do |config|
|
|
137
150
|
config.csp = {
|
|
138
|
-
default_src: %w(https:)
|
|
151
|
+
default_src: %w(https:),
|
|
152
|
+
script_src: %w('self'),
|
|
139
153
|
}
|
|
140
154
|
end
|
|
141
|
-
combined_config = ContentSecurityPolicy.combine_policies(Configuration.get.csp.to_h,
|
|
155
|
+
combined_config = ContentSecurityPolicy.combine_policies(Configuration.get.csp.to_h, style_src: %w(anothercdn.com))
|
|
142
156
|
csp = ContentSecurityPolicy.new(combined_config)
|
|
143
157
|
expect(csp.name).to eq(ContentSecurityPolicyConfig::HEADER_NAME)
|
|
144
|
-
expect(csp.value).to eq("default-src https:; script-src https: anothercdn.com")
|
|
158
|
+
expect(csp.value).to eq("default-src https:; script-src 'self'; style-src https: anothercdn.com")
|
|
145
159
|
end
|
|
146
160
|
|
|
147
161
|
it "combines directives where the original value is nil and the hash is frozen" do
|
|
148
162
|
Configuration.default do |config|
|
|
149
163
|
config.csp = {
|
|
150
164
|
default_src: %w('self'),
|
|
165
|
+
script_src: %w('self'),
|
|
151
166
|
report_only: false
|
|
152
167
|
}.freeze
|
|
153
168
|
end
|
|
@@ -161,6 +176,7 @@ module SecureHeaders
|
|
|
161
176
|
Configuration.default do |config|
|
|
162
177
|
config.csp = {
|
|
163
178
|
default_src: %w('self'),
|
|
179
|
+
script_src: %w('self'),
|
|
164
180
|
report_only: false
|
|
165
181
|
}.freeze
|
|
166
182
|
end
|
|
@@ -172,14 +188,13 @@ module SecureHeaders
|
|
|
172
188
|
ContentSecurityPolicy::NON_FETCH_SOURCES.each do |directive|
|
|
173
189
|
expect(combined_config[directive]).to eq(%w("http://example.org))
|
|
174
190
|
end
|
|
175
|
-
|
|
176
|
-
ContentSecurityPolicy.new(combined_config, USER_AGENTS[:firefox]).value
|
|
177
191
|
end
|
|
178
192
|
|
|
179
193
|
it "overrides the report_only flag" do
|
|
180
194
|
Configuration.default do |config|
|
|
181
195
|
config.csp = {
|
|
182
196
|
default_src: %w('self'),
|
|
197
|
+
script_src: %w('self'),
|
|
183
198
|
report_only: false
|
|
184
199
|
}
|
|
185
200
|
end
|
|
@@ -192,12 +207,13 @@ module SecureHeaders
|
|
|
192
207
|
Configuration.default do |config|
|
|
193
208
|
config.csp = {
|
|
194
209
|
default_src: %w(https:),
|
|
210
|
+
script_src: %w('self'),
|
|
195
211
|
block_all_mixed_content: false
|
|
196
212
|
}
|
|
197
213
|
end
|
|
198
214
|
combined_config = ContentSecurityPolicy.combine_policies(Configuration.get.csp.to_h, block_all_mixed_content: true)
|
|
199
215
|
csp = ContentSecurityPolicy.new(combined_config)
|
|
200
|
-
expect(csp.value).to eq("default-src https:; block-all-mixed-content")
|
|
216
|
+
expect(csp.value).to eq("default-src https:; block-all-mixed-content; script-src 'self'")
|
|
201
217
|
end
|
|
202
218
|
|
|
203
219
|
it "raises an error if appending to a OPT_OUT policy" do
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require "spec_helper"
|
|
2
3
|
|
|
3
4
|
module SecureHeaders
|
|
4
5
|
describe PublicKeyPins do
|
|
@@ -8,7 +9,7 @@ module SecureHeaders
|
|
|
8
9
|
specify { expect(PublicKeyPins.new(max_age: 1234).value).to eq("max-age=1234") }
|
|
9
10
|
specify { expect(PublicKeyPins.new(max_age: 1234).value).to eq("max-age=1234") }
|
|
10
11
|
specify do
|
|
11
|
-
config = { max_age: 1234, pins: [{ sha256:
|
|
12
|
+
config = { max_age: 1234, pins: [{ sha256: "base64encodedpin1" }, { sha256: "base64encodedpin2" }] }
|
|
12
13
|
header_value = "max-age=1234; pin-sha256=\"base64encodedpin1\"; pin-sha256=\"base64encodedpin2\""
|
|
13
14
|
expect(PublicKeyPins.new(config).value).to eq(header_value)
|
|
14
15
|
end
|
|
@@ -16,19 +17,19 @@ module SecureHeaders
|
|
|
16
17
|
context "with an invalid configuration" do
|
|
17
18
|
it "raises an exception when max-age is not provided" do
|
|
18
19
|
expect do
|
|
19
|
-
PublicKeyPins.validate_config!(foo:
|
|
20
|
+
PublicKeyPins.validate_config!(foo: "bar")
|
|
20
21
|
end.to raise_error(PublicKeyPinsConfigError)
|
|
21
22
|
end
|
|
22
23
|
|
|
23
24
|
it "raises an exception with an invalid max-age" do
|
|
24
25
|
expect do
|
|
25
|
-
PublicKeyPins.validate_config!(max_age:
|
|
26
|
+
PublicKeyPins.validate_config!(max_age: "abc123")
|
|
26
27
|
end.to raise_error(PublicKeyPinsConfigError)
|
|
27
28
|
end
|
|
28
29
|
|
|
29
|
-
it
|
|
30
|
+
it "raises an exception with less than 2 pins" do
|
|
30
31
|
expect do
|
|
31
|
-
config = { max_age: 1234, pins: [{ sha256:
|
|
32
|
+
config = { max_age: 1234, pins: [{ sha256: "base64encodedpin" }] }
|
|
32
33
|
PublicKeyPins.validate_config!(config)
|
|
33
34
|
end.to raise_error(PublicKeyPinsConfigError)
|
|
34
35
|
end
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require "spec_helper"
|
|
2
3
|
|
|
3
4
|
module SecureHeaders
|
|
4
5
|
describe ReferrerPolicy do
|
|
5
6
|
specify { expect(ReferrerPolicy.make_header).to eq([ReferrerPolicy::HEADER_NAME, "origin-when-cross-origin"]) }
|
|
6
|
-
specify { expect(ReferrerPolicy.make_header(
|
|
7
|
+
specify { expect(ReferrerPolicy.make_header("no-referrer")).to eq([ReferrerPolicy::HEADER_NAME, "no-referrer"]) }
|
|
7
8
|
|
|
8
9
|
context "valid configuration values" do
|
|
9
10
|
it "accepts 'no-referrer'" do
|
|
@@ -61,7 +62,7 @@ module SecureHeaders
|
|
|
61
62
|
end
|
|
62
63
|
end
|
|
63
64
|
|
|
64
|
-
context
|
|
65
|
+
context "invlaid configuration values" do
|
|
65
66
|
it "doesn't accept invalid values" do
|
|
66
67
|
expect do
|
|
67
68
|
ReferrerPolicy.validate_config!("open")
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require "spec_helper"
|
|
2
3
|
|
|
3
4
|
module SecureHeaders
|
|
4
5
|
describe StrictTransportSecurity do
|
|
@@ -10,19 +11,19 @@ module SecureHeaders
|
|
|
10
11
|
context "with a string argument" do
|
|
11
12
|
it "raises an exception with an invalid max-age" do
|
|
12
13
|
expect do
|
|
13
|
-
StrictTransportSecurity.validate_config!(
|
|
14
|
+
StrictTransportSecurity.validate_config!("max-age=abc123")
|
|
14
15
|
end.to raise_error(STSConfigError)
|
|
15
16
|
end
|
|
16
17
|
|
|
17
18
|
it "raises an exception if max-age is not supplied" do
|
|
18
19
|
expect do
|
|
19
|
-
StrictTransportSecurity.validate_config!(
|
|
20
|
+
StrictTransportSecurity.validate_config!("includeSubdomains")
|
|
20
21
|
end.to raise_error(STSConfigError)
|
|
21
22
|
end
|
|
22
23
|
|
|
23
24
|
it "raises an exception with an invalid format" do
|
|
24
25
|
expect do
|
|
25
|
-
StrictTransportSecurity.validate_config!(
|
|
26
|
+
StrictTransportSecurity.validate_config!("max-age=123includeSubdomains")
|
|
26
27
|
end.to raise_error(STSConfigError)
|
|
27
28
|
end
|
|
28
29
|
end
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require "spec_helper"
|
|
2
3
|
|
|
3
4
|
module SecureHeaders
|
|
4
5
|
describe XDownloadOptions do
|
|
5
6
|
specify { expect(XDownloadOptions.make_header).to eq([XDownloadOptions::HEADER_NAME, XDownloadOptions::DEFAULT_VALUE]) }
|
|
6
|
-
specify { expect(XDownloadOptions.make_header(
|
|
7
|
+
specify { expect(XDownloadOptions.make_header("noopen")).to eq([XDownloadOptions::HEADER_NAME, "noopen"]) }
|
|
7
8
|
|
|
8
9
|
context "invalid configuration values" do
|
|
9
10
|
it "accepts noopen" do
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require "spec_helper"
|
|
2
3
|
|
|
3
4
|
module SecureHeaders
|
|
4
5
|
describe XPermittedCrossDomainPolicies do
|
|
5
6
|
specify { expect(XPermittedCrossDomainPolicies.make_header).to eq([XPermittedCrossDomainPolicies::HEADER_NAME, "none"]) }
|
|
6
|
-
specify { expect(XPermittedCrossDomainPolicies.make_header(
|
|
7
|
+
specify { expect(XPermittedCrossDomainPolicies.make_header("master-only")).to eq([XPermittedCrossDomainPolicies::HEADER_NAME, "master-only"]) }
|
|
7
8
|
|
|
8
9
|
context "valid configuration values" do
|
|
9
10
|
it "accepts 'all'" do
|
|
@@ -36,7 +37,7 @@ module SecureHeaders
|
|
|
36
37
|
end
|
|
37
38
|
end
|
|
38
39
|
|
|
39
|
-
context
|
|
40
|
+
context "invlaid configuration values" do
|
|
40
41
|
it "doesn't accept invalid values" do
|
|
41
42
|
expect do
|
|
42
43
|
XPermittedCrossDomainPolicies.validate_config!("open")
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require "spec_helper"
|
|
2
3
|
|
|
3
4
|
module SecureHeaders
|
|
4
5
|
describe XXssProtection do
|
|
5
6
|
specify { expect(XXssProtection.make_header).to eq([XXssProtection::HEADER_NAME, XXssProtection::DEFAULT_VALUE]) }
|
|
6
|
-
specify { expect(XXssProtection.make_header("1; mode=block; report=https://www.secure.com/reports")).to eq([XXssProtection::HEADER_NAME,
|
|
7
|
+
specify { expect(XXssProtection.make_header("1; mode=block; report=https://www.secure.com/reports")).to eq([XXssProtection::HEADER_NAME, "1; mode=block; report=https://www.secure.com/reports"]) }
|
|
7
8
|
|
|
8
9
|
context "with invalid configuration" do
|
|
9
10
|
it "should raise an error when providing a string that is not valid" do
|
|
@@ -19,7 +20,7 @@ module SecureHeaders
|
|
|
19
20
|
context "when using a hash value" do
|
|
20
21
|
it "should allow string values ('1' or '0' are the only valid strings)" do
|
|
21
22
|
expect do
|
|
22
|
-
XXssProtection.validate_config!(
|
|
23
|
+
XXssProtection.validate_config!("1")
|
|
23
24
|
end.not_to raise_error
|
|
24
25
|
end
|
|
25
26
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
require "spec_helper"
|
|
2
3
|
|
|
3
4
|
module SecureHeaders
|
|
@@ -19,8 +20,8 @@ module SecureHeaders
|
|
|
19
20
|
config.hpkp = {
|
|
20
21
|
max_age: 10000000,
|
|
21
22
|
pins: [
|
|
22
|
-
{sha256:
|
|
23
|
-
{sha256:
|
|
23
|
+
{sha256: "b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c"},
|
|
24
|
+
{sha256: "73a2c64f9545172c1195efb6616ca5f7afd1df6f245407cafb90de3998a1c97f"}
|
|
24
25
|
],
|
|
25
26
|
report_uri: "https://#{report_host}/example-hpkp"
|
|
26
27
|
}
|
|
@@ -54,68 +55,75 @@ module SecureHeaders
|
|
|
54
55
|
expect(env[ContentSecurityPolicyConfig::HEADER_NAME]).to match("example.org")
|
|
55
56
|
end
|
|
56
57
|
|
|
57
|
-
context "
|
|
58
|
+
context "cookies" do
|
|
58
59
|
context "cookies should be flagged" do
|
|
59
60
|
it "flags cookies as secure" do
|
|
60
|
-
|
|
61
|
-
Configuration.default { |config| config.secure_cookies = true }
|
|
62
|
-
end
|
|
61
|
+
Configuration.default { |config| config.cookies = {secure: true, httponly: OPT_OUT, samesite: OPT_OUT} }
|
|
63
62
|
request = Rack::Request.new("HTTPS" => "on")
|
|
64
63
|
_, env = cookie_middleware.call request.env
|
|
65
|
-
expect(env[
|
|
64
|
+
expect(env["Set-Cookie"]).to eq("foo=bar; secure")
|
|
66
65
|
end
|
|
67
66
|
end
|
|
68
67
|
|
|
68
|
+
it "allows opting out of cookie protection with OPT_OUT alone" do
|
|
69
|
+
Configuration.default { |config| config.cookies = OPT_OUT}
|
|
70
|
+
|
|
71
|
+
# do NOT make this request https. non-https requests modify a config,
|
|
72
|
+
# causing an exception when operating on OPT_OUT. This ensures we don't
|
|
73
|
+
# try to modify the config.
|
|
74
|
+
request = Rack::Request.new({})
|
|
75
|
+
_, env = cookie_middleware.call request.env
|
|
76
|
+
expect(env["Set-Cookie"]).to eq("foo=bar")
|
|
77
|
+
end
|
|
78
|
+
|
|
69
79
|
context "cookies should not be flagged" do
|
|
70
80
|
it "does not flags cookies as secure" do
|
|
71
|
-
|
|
72
|
-
Configuration.default { |config| config.secure_cookies = false }
|
|
73
|
-
end
|
|
81
|
+
Configuration.default { |config| config.cookies = {secure: OPT_OUT, httponly: OPT_OUT, samesite: OPT_OUT} }
|
|
74
82
|
request = Rack::Request.new("HTTPS" => "on")
|
|
75
83
|
_, env = cookie_middleware.call request.env
|
|
76
|
-
expect(env[
|
|
84
|
+
expect(env["Set-Cookie"]).to eq("foo=bar")
|
|
77
85
|
end
|
|
78
86
|
end
|
|
79
87
|
end
|
|
80
88
|
|
|
81
89
|
context "cookies" do
|
|
82
90
|
it "flags cookies from configuration" do
|
|
83
|
-
Configuration.default { |config| config.cookies = { secure: true, httponly: true } }
|
|
91
|
+
Configuration.default { |config| config.cookies = { secure: true, httponly: true, samesite: { lax: true} } }
|
|
84
92
|
request = Rack::Request.new("HTTPS" => "on")
|
|
85
93
|
_, env = cookie_middleware.call request.env
|
|
86
94
|
|
|
87
|
-
expect(env[
|
|
95
|
+
expect(env["Set-Cookie"]).to eq("foo=bar; secure; HttpOnly; SameSite=Lax")
|
|
88
96
|
end
|
|
89
97
|
|
|
90
98
|
it "flags cookies with a combination of SameSite configurations" do
|
|
91
99
|
cookie_middleware = Middleware.new(lambda { |env| [200, env.merge("Set-Cookie" => ["_session=foobar", "_guest=true"]), "app"] })
|
|
92
100
|
|
|
93
|
-
Configuration.default { |config| config.cookies = { samesite: { lax: { except: ["_session"] }, strict: { only: ["_session"] } } } }
|
|
101
|
+
Configuration.default { |config| config.cookies = { samesite: { lax: { except: ["_session"] }, strict: { only: ["_session"] } }, httponly: OPT_OUT, secure: OPT_OUT} }
|
|
94
102
|
request = Rack::Request.new("HTTPS" => "on")
|
|
95
103
|
_, env = cookie_middleware.call request.env
|
|
96
104
|
|
|
97
|
-
expect(env[
|
|
98
|
-
expect(env[
|
|
105
|
+
expect(env["Set-Cookie"]).to match("_session=foobar; SameSite=Strict")
|
|
106
|
+
expect(env["Set-Cookie"]).to match("_guest=true; SameSite=Lax")
|
|
99
107
|
end
|
|
100
108
|
|
|
101
109
|
it "disables secure cookies for non-https requests" do
|
|
102
|
-
Configuration.default { |config| config.cookies = { secure: true } }
|
|
110
|
+
Configuration.default { |config| config.cookies = { secure: true, httponly: OPT_OUT, samesite: OPT_OUT } }
|
|
103
111
|
|
|
104
112
|
request = Rack::Request.new("HTTPS" => "off")
|
|
105
113
|
_, env = cookie_middleware.call request.env
|
|
106
|
-
expect(env[
|
|
114
|
+
expect(env["Set-Cookie"]).to eq("foo=bar")
|
|
107
115
|
end
|
|
108
116
|
|
|
109
117
|
it "sets the secure cookie flag correctly on interleaved http/https requests" do
|
|
110
|
-
Configuration.default { |config| config.cookies = { secure: true } }
|
|
118
|
+
Configuration.default { |config| config.cookies = { secure: true, httponly: OPT_OUT, samesite: OPT_OUT } }
|
|
111
119
|
|
|
112
120
|
request = Rack::Request.new("HTTPS" => "off")
|
|
113
121
|
_, env = cookie_middleware.call request.env
|
|
114
|
-
expect(env[
|
|
122
|
+
expect(env["Set-Cookie"]).to eq("foo=bar")
|
|
115
123
|
|
|
116
124
|
request = Rack::Request.new("HTTPS" => "on")
|
|
117
125
|
_, env = cookie_middleware.call request.env
|
|
118
|
-
expect(env[
|
|
126
|
+
expect(env["Set-Cookie"]).to eq("foo=bar; secure")
|
|
119
127
|
end
|
|
120
128
|
end
|
|
121
129
|
end
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
require "spec_helper"
|
|
2
3
|
require "erb"
|
|
3
4
|
|
|
@@ -58,7 +59,7 @@ TEMPLATE
|
|
|
58
59
|
end
|
|
59
60
|
|
|
60
61
|
if options.is_a?(Hash)
|
|
61
|
-
options = options.map {|k,v| " #{k}=#{v}"}
|
|
62
|
+
options = options.map {|k, v| " #{k}=#{v}"}
|
|
62
63
|
end
|
|
63
64
|
"<#{type}#{options}>#{content}</#{type}>"
|
|
64
65
|
end
|
|
@@ -82,9 +83,9 @@ module SecureHeaders
|
|
|
82
83
|
before(:all) do
|
|
83
84
|
Configuration.default do |config|
|
|
84
85
|
config.csp = {
|
|
85
|
-
:
|
|
86
|
-
:
|
|
87
|
-
:
|
|
86
|
+
default_src: %w('self'),
|
|
87
|
+
script_src: %w('self'),
|
|
88
|
+
style_src: %w('self')
|
|
88
89
|
}
|
|
89
90
|
end
|
|
90
91
|
end
|