secure_headers 3.7.2 → 4.0.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/.rspec +1 -0
- data/.rubocop.yml +3 -0
- data/.ruby-version +1 -1
- data/.travis.yml +8 -6
- data/CHANGELOG.md +2 -6
- data/CONTRIBUTING.md +1 -1
- data/Gemfile +7 -4
- data/Guardfile +1 -0
- data/README.md +7 -19
- data/Rakefile +22 -18
- data/docs/cookies.md +16 -2
- 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 +12 -15
- data/lib/secure_headers/headers/content_security_policy_config.rb +1 -1
- data/lib/secure_headers/headers/cookie.rb +21 -3
- data/lib/secure_headers/headers/expect_certificate_transparency.rb +1 -1
- data/lib/secure_headers/headers/policy_management.rb +14 -8
- 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 +13 -12
- 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 +18 -18
- data/spec/lib/secure_headers/headers/cookie_spec.rb +38 -20
- data/spec/lib/secure_headers/headers/policy_management_spec.rb +26 -11
- 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 +13 -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
|
|
|
@@ -32,7 +33,6 @@ module SecureHeaders
|
|
|
32
33
|
object_src: %w('self'),
|
|
33
34
|
script_src: %w('self'),
|
|
34
35
|
style_src: %w('unsafe-inline'),
|
|
35
|
-
worker_src: %w(worker.com),
|
|
36
36
|
base_uri: %w('self'),
|
|
37
37
|
form_action: %w('self' github.com),
|
|
38
38
|
frame_ancestors: %w('none'),
|
|
@@ -47,10 +47,22 @@ module SecureHeaders
|
|
|
47
47
|
|
|
48
48
|
it "requires a :default_src value" do
|
|
49
49
|
expect do
|
|
50
|
-
ContentSecurityPolicy.validate_config!(ContentSecurityPolicyConfig.new(script_src: %('self')))
|
|
50
|
+
ContentSecurityPolicy.validate_config!(ContentSecurityPolicyConfig.new(script_src: %w('self')))
|
|
51
51
|
end.to raise_error(ContentSecurityPolicyConfigError)
|
|
52
52
|
end
|
|
53
53
|
|
|
54
|
+
it "requires a :script_src value" do
|
|
55
|
+
expect do
|
|
56
|
+
ContentSecurityPolicy.validate_config!(ContentSecurityPolicyConfig.new(default_src: %w('self')))
|
|
57
|
+
end.to raise_error(ContentSecurityPolicyConfigError)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it "accepts OPT_OUT as a script-src value" do
|
|
61
|
+
expect do
|
|
62
|
+
ContentSecurityPolicy.validate_config!(ContentSecurityPolicyConfig.new(default_src: %w('self'), script_src: OPT_OUT))
|
|
63
|
+
end.to_not raise_error
|
|
64
|
+
end
|
|
65
|
+
|
|
54
66
|
it "requires :report_only to be a truthy value" do
|
|
55
67
|
expect do
|
|
56
68
|
ContentSecurityPolicy.validate_config!(ContentSecurityPolicyConfig.new(default_opts.merge(report_only: "steve")))
|
|
@@ -96,7 +108,7 @@ module SecureHeaders
|
|
|
96
108
|
# this is mostly to ensure people don't use the antiquated shorthands common in other configs
|
|
97
109
|
it "performs light validation on source lists" do
|
|
98
110
|
expect do
|
|
99
|
-
ContentSecurityPolicy.validate_config!(ContentSecurityPolicyConfig.new(default_src: %w(self none inline eval)))
|
|
111
|
+
ContentSecurityPolicy.validate_config!(ContentSecurityPolicyConfig.new(default_src: %w(self none inline eval), script_src: %w('self')))
|
|
100
112
|
end.to raise_error(ContentSecurityPolicyConfigError)
|
|
101
113
|
end
|
|
102
114
|
|
|
@@ -135,19 +147,21 @@ module SecureHeaders
|
|
|
135
147
|
it "combines the default-src value with the override if the directive was unconfigured" do
|
|
136
148
|
Configuration.default do |config|
|
|
137
149
|
config.csp = {
|
|
138
|
-
default_src: %w(https:)
|
|
150
|
+
default_src: %w(https:),
|
|
151
|
+
script_src: %w('self'),
|
|
139
152
|
}
|
|
140
153
|
end
|
|
141
|
-
combined_config = ContentSecurityPolicy.combine_policies(Configuration.get.csp.to_h,
|
|
154
|
+
combined_config = ContentSecurityPolicy.combine_policies(Configuration.get.csp.to_h, style_src: %w(anothercdn.com))
|
|
142
155
|
csp = ContentSecurityPolicy.new(combined_config)
|
|
143
156
|
expect(csp.name).to eq(ContentSecurityPolicyConfig::HEADER_NAME)
|
|
144
|
-
expect(csp.value).to eq("default-src https:; script-src https: anothercdn.com")
|
|
157
|
+
expect(csp.value).to eq("default-src https:; script-src 'self'; style-src https: anothercdn.com")
|
|
145
158
|
end
|
|
146
159
|
|
|
147
160
|
it "combines directives where the original value is nil and the hash is frozen" do
|
|
148
161
|
Configuration.default do |config|
|
|
149
162
|
config.csp = {
|
|
150
163
|
default_src: %w('self'),
|
|
164
|
+
script_src: %w('self'),
|
|
151
165
|
report_only: false
|
|
152
166
|
}.freeze
|
|
153
167
|
end
|
|
@@ -161,6 +175,7 @@ module SecureHeaders
|
|
|
161
175
|
Configuration.default do |config|
|
|
162
176
|
config.csp = {
|
|
163
177
|
default_src: %w('self'),
|
|
178
|
+
script_src: %w('self'),
|
|
164
179
|
report_only: false
|
|
165
180
|
}.freeze
|
|
166
181
|
end
|
|
@@ -172,14 +187,13 @@ module SecureHeaders
|
|
|
172
187
|
ContentSecurityPolicy::NON_FETCH_SOURCES.each do |directive|
|
|
173
188
|
expect(combined_config[directive]).to eq(%w("http://example.org))
|
|
174
189
|
end
|
|
175
|
-
|
|
176
|
-
ContentSecurityPolicy.new(combined_config, USER_AGENTS[:firefox]).value
|
|
177
190
|
end
|
|
178
191
|
|
|
179
192
|
it "overrides the report_only flag" do
|
|
180
193
|
Configuration.default do |config|
|
|
181
194
|
config.csp = {
|
|
182
195
|
default_src: %w('self'),
|
|
196
|
+
script_src: %w('self'),
|
|
183
197
|
report_only: false
|
|
184
198
|
}
|
|
185
199
|
end
|
|
@@ -192,12 +206,13 @@ module SecureHeaders
|
|
|
192
206
|
Configuration.default do |config|
|
|
193
207
|
config.csp = {
|
|
194
208
|
default_src: %w(https:),
|
|
209
|
+
script_src: %w('self'),
|
|
195
210
|
block_all_mixed_content: false
|
|
196
211
|
}
|
|
197
212
|
end
|
|
198
213
|
combined_config = ContentSecurityPolicy.combine_policies(Configuration.get.csp.to_h, block_all_mixed_content: true)
|
|
199
214
|
csp = ContentSecurityPolicy.new(combined_config)
|
|
200
|
-
expect(csp.value).to eq("default-src https:; block-all-mixed-content")
|
|
215
|
+
expect(csp.value).to eq("default-src https:; block-all-mixed-content; script-src 'self'")
|
|
201
216
|
end
|
|
202
217
|
|
|
203
218
|
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
|