secure_headers 3.5.0.pre → 3.6.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 +4 -4
- data/.ruby-version +1 -1
- data/.travis.yml +2 -0
- data/CHANGELOG.md +20 -1
- data/Gemfile +1 -0
- data/LICENSE +4 -199
- data/README.md +37 -388
- data/docs/HPKP.md +17 -0
- data/docs/cookies.md +50 -0
- data/docs/hashes.md +64 -0
- data/docs/named_overrides_and_appends.md +107 -0
- data/docs/per_action_configuration.md +105 -0
- data/docs/sinatra.md +25 -0
- data/lib/secure_headers/configuration.rb +5 -3
- data/lib/secure_headers/headers/clear_site_data.rb +51 -0
- data/lib/secure_headers/headers/content_security_policy.rb +6 -2
- data/lib/secure_headers/headers/content_security_policy_config.rb +21 -12
- data/lib/secure_headers/headers/policy_management.rb +14 -2
- data/lib/secure_headers/headers/referrer_policy.rb +4 -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 +1 -1
- data/lib/secure_headers/headers/x_frame_options.rb +1 -1
- data/lib/secure_headers/headers/x_permitted_cross_domain_policies.rb +1 -1
- data/lib/secure_headers/headers/x_xss_protection.rb +1 -1
- data/lib/secure_headers/view_helper.rb +8 -0
- data/lib/secure_headers.rb +4 -1
- data/secure_headers.gemspec +1 -1
- data/spec/lib/secure_headers/headers/clear_site_data_spec.rb +103 -0
- data/spec/lib/secure_headers/headers/content_security_policy_spec.rb +17 -0
- data/spec/lib/secure_headers/headers/referrer_policy_spec.rb +18 -0
- data/spec/lib/secure_headers/middleware_spec.rb +12 -0
- data/spec/lib/secure_headers/view_helpers_spec.rb +10 -0
- data/spec/lib/secure_headers_spec.rb +22 -0
- data/spec/spec_helper.rb +2 -1
- metadata +14 -5
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module SecureHeaders
|
|
4
|
+
describe ClearSiteData do
|
|
5
|
+
describe "make_header" do
|
|
6
|
+
it "returns nil with nil config" do
|
|
7
|
+
expect(described_class.make_header).to be_nil
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it "returns nil with empty config" do
|
|
11
|
+
expect(described_class.make_header([])).to be_nil
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "returns nil with opt-out config" do
|
|
15
|
+
expect(described_class.make_header(OPT_OUT)).to be_nil
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "returns all types with `true` config" do
|
|
19
|
+
name, value = described_class.make_header(true)
|
|
20
|
+
|
|
21
|
+
expect(name).to eq(ClearSiteData::HEADER_NAME)
|
|
22
|
+
expect(value).to eq(normalize_json(<<-HERE))
|
|
23
|
+
{
|
|
24
|
+
"types": [
|
|
25
|
+
"cache",
|
|
26
|
+
"cookies",
|
|
27
|
+
"storage",
|
|
28
|
+
"executionContexts"
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
HERE
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "returns specified types" do
|
|
35
|
+
name, value = described_class.make_header(["foo", "bar"])
|
|
36
|
+
|
|
37
|
+
expect(name).to eq(ClearSiteData::HEADER_NAME)
|
|
38
|
+
expect(value).to eq(normalize_json(<<-HERE))
|
|
39
|
+
{
|
|
40
|
+
"types": [
|
|
41
|
+
"foo",
|
|
42
|
+
"bar"
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
HERE
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
describe "validate_config!" do
|
|
50
|
+
it "succeeds for `true` config" do
|
|
51
|
+
expect do
|
|
52
|
+
described_class.validate_config!(true)
|
|
53
|
+
end.not_to raise_error
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it "succeeds for `nil` config" do
|
|
57
|
+
expect do
|
|
58
|
+
described_class.validate_config!(nil)
|
|
59
|
+
end.not_to raise_error
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "succeeds for opt-out config" do
|
|
63
|
+
expect do
|
|
64
|
+
described_class.validate_config!(OPT_OUT)
|
|
65
|
+
end.not_to raise_error
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
it "succeeds for empty config" do
|
|
69
|
+
expect do
|
|
70
|
+
described_class.validate_config!([])
|
|
71
|
+
end.not_to raise_error
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it "succeeds for Array of Strings config" do
|
|
75
|
+
expect do
|
|
76
|
+
described_class.validate_config!(["foo"])
|
|
77
|
+
end.not_to raise_error
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it "fails for Array of non-String config" do
|
|
81
|
+
expect do
|
|
82
|
+
described_class.validate_config!([1])
|
|
83
|
+
end.to raise_error(ClearSiteDataConfigError)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it "fails for non-serializable config" do
|
|
87
|
+
expect do
|
|
88
|
+
described_class.validate_config!(["hi \255"])
|
|
89
|
+
end.to raise_error(ClearSiteDataConfigError)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it "fails for other types of config" do
|
|
93
|
+
expect do
|
|
94
|
+
described_class.validate_config!(:cookies)
|
|
95
|
+
end.to raise_error(ClearSiteDataConfigError)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def normalize_json(json)
|
|
100
|
+
JSON.dump(JSON.parse(json))
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
@@ -107,6 +107,11 @@ module SecureHeaders
|
|
|
107
107
|
expect(firefox_transitional).not_to match(/frame-src/)
|
|
108
108
|
end
|
|
109
109
|
|
|
110
|
+
it "supports strict-dynamic" do
|
|
111
|
+
csp = ContentSecurityPolicy.new({default_src: %w('self'), script_src: [ContentSecurityPolicy::STRICT_DYNAMIC], script_nonce: 123456}, USER_AGENTS[:chrome])
|
|
112
|
+
expect(csp.value).to eq("default-src 'self'; script-src 'strict-dynamic' 'nonce-123456'")
|
|
113
|
+
end
|
|
114
|
+
|
|
110
115
|
context "browser sniffing" do
|
|
111
116
|
let (:complex_opts) do
|
|
112
117
|
(ContentSecurityPolicy::ALL_DIRECTIVES - [:frame_src]).each_with_object({}) do |directive, hash|
|
|
@@ -149,6 +154,18 @@ module SecureHeaders
|
|
|
149
154
|
policy = ContentSecurityPolicy.new(complex_opts, USER_AGENTS[:safari6])
|
|
150
155
|
expect(policy.value).to eq("default-src default-src.com; connect-src connect-src.com; font-src font-src.com; frame-src child-src.com; img-src img-src.com; media-src media-src.com; object-src object-src.com; sandbox sandbox.com; script-src script-src.com 'unsafe-inline'; style-src style-src.com; report-uri report-uri.com")
|
|
151
156
|
end
|
|
157
|
+
|
|
158
|
+
it "adds 'unsafe-inline', filters blocked-all-mixed-content, upgrade-insecure-requests, nonce sources, and hash sources for safari 10 and higher" do
|
|
159
|
+
policy = ContentSecurityPolicy.new(complex_opts, USER_AGENTS[:safari10])
|
|
160
|
+
expect(policy.value).to eq("default-src default-src.com; base-uri base-uri.com; child-src child-src.com; connect-src connect-src.com; font-src font-src.com; form-action form-action.com; frame-ancestors frame-ancestors.com; img-src img-src.com; media-src media-src.com; object-src object-src.com; plugin-types plugin-types.com; sandbox sandbox.com; script-src script-src.com 'nonce-123456'; style-src style-src.com; report-uri report-uri.com")
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
it "falls back to standard Firefox defaults when the useragent version is not present" do
|
|
164
|
+
ua = USER_AGENTS[:firefox].dup
|
|
165
|
+
allow(ua).to receive(:version).and_return(nil)
|
|
166
|
+
policy = ContentSecurityPolicy.new(complex_opts, ua)
|
|
167
|
+
expect(policy.value).to eq("default-src default-src.com; base-uri base-uri.com; connect-src connect-src.com; font-src font-src.com; form-action form-action.com; frame-ancestors frame-ancestors.com; frame-src child-src.com; img-src img-src.com; media-src media-src.com; object-src object-src.com; sandbox sandbox.com; script-src script-src.com 'nonce-123456'; style-src style-src.com; upgrade-insecure-requests; report-uri report-uri.com")
|
|
168
|
+
end
|
|
152
169
|
end
|
|
153
170
|
end
|
|
154
171
|
end
|
|
@@ -18,6 +18,24 @@ module SecureHeaders
|
|
|
18
18
|
end.not_to raise_error
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
+
it "accepts 'same-origin'" do
|
|
22
|
+
expect do
|
|
23
|
+
ReferrerPolicy.validate_config!("same-origin")
|
|
24
|
+
end.not_to raise_error
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "accepts 'strict-origin'" do
|
|
28
|
+
expect do
|
|
29
|
+
ReferrerPolicy.validate_config!("strict-origin")
|
|
30
|
+
end.not_to raise_error
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "accepts 'strict-origin-when-cross-origin'" do
|
|
34
|
+
expect do
|
|
35
|
+
ReferrerPolicy.validate_config!("strict-origin-when-cross-origin")
|
|
36
|
+
end.not_to raise_error
|
|
37
|
+
end
|
|
38
|
+
|
|
21
39
|
it "accepts 'origin'" do
|
|
22
40
|
expect do
|
|
23
41
|
ReferrerPolicy.validate_config!("origin")
|
|
@@ -105,6 +105,18 @@ module SecureHeaders
|
|
|
105
105
|
_, env = cookie_middleware.call request.env
|
|
106
106
|
expect(env['Set-Cookie']).to eq("foo=bar")
|
|
107
107
|
end
|
|
108
|
+
|
|
109
|
+
it "sets the secure cookie flag correctly on interleaved http/https requests" do
|
|
110
|
+
Configuration.default { |config| config.cookies = { secure: true } }
|
|
111
|
+
|
|
112
|
+
request = Rack::Request.new("HTTPS" => "off")
|
|
113
|
+
_, env = cookie_middleware.call request.env
|
|
114
|
+
expect(env['Set-Cookie']).to eq("foo=bar")
|
|
115
|
+
|
|
116
|
+
request = Rack::Request.new("HTTPS" => "on")
|
|
117
|
+
_, env = cookie_middleware.call request.env
|
|
118
|
+
expect(env['Set-Cookie']).to eq("foo=bar; secure")
|
|
119
|
+
end
|
|
108
120
|
end
|
|
109
121
|
end
|
|
110
122
|
end
|
|
@@ -27,6 +27,16 @@ class Message < ERB
|
|
|
27
27
|
background-color: black;
|
|
28
28
|
}
|
|
29
29
|
<% end %>
|
|
30
|
+
|
|
31
|
+
<script nonce="<%= content_security_policy_script_nonce %>">
|
|
32
|
+
alert(1)
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<style nonce="<%= content_security_policy_style_nonce %>">
|
|
36
|
+
body {
|
|
37
|
+
background-color: black;
|
|
38
|
+
}
|
|
39
|
+
</style>
|
|
30
40
|
<%= @name %>
|
|
31
41
|
|
|
32
42
|
TEMPLATE
|
|
@@ -277,6 +277,20 @@ module SecureHeaders
|
|
|
277
277
|
expect(hash['Content-Security-Policy']).to eq("default-src 'self'; script-src mycdn.com 'nonce-#{nonce}'; style-src 'self'")
|
|
278
278
|
end
|
|
279
279
|
|
|
280
|
+
it "uses a nonce for safari 10+" do
|
|
281
|
+
Configuration.default do |config|
|
|
282
|
+
config.csp = {
|
|
283
|
+
default_src: %w('self'),
|
|
284
|
+
script_src: %w(mycdn.com)
|
|
285
|
+
}
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
safari_request = Rack::Request.new(request.env.merge("HTTP_USER_AGENT" => USER_AGENTS[:safari10]))
|
|
289
|
+
nonce = SecureHeaders.content_security_policy_script_nonce(safari_request)
|
|
290
|
+
hash = SecureHeaders.header_hash_for(safari_request)
|
|
291
|
+
expect(hash['Content-Security-Policy']).to eq("default-src 'self'; script-src mycdn.com 'nonce-#{nonce}'")
|
|
292
|
+
end
|
|
293
|
+
|
|
280
294
|
it "supports the deprecated `report_only: true` format" do
|
|
281
295
|
expect(Kernel).to receive(:warn).once
|
|
282
296
|
|
|
@@ -516,6 +530,14 @@ module SecureHeaders
|
|
|
516
530
|
end.to raise_error(XContentTypeOptionsConfigError)
|
|
517
531
|
end
|
|
518
532
|
|
|
533
|
+
it "validates your clear site data config upon configuration" do
|
|
534
|
+
expect do
|
|
535
|
+
Configuration.default do |config|
|
|
536
|
+
config.clear_site_data = 1
|
|
537
|
+
end
|
|
538
|
+
end.to raise_error(ClearSiteDataConfigError)
|
|
539
|
+
end
|
|
540
|
+
|
|
519
541
|
it "validates your x_xss config upon configuration" do
|
|
520
542
|
expect do
|
|
521
543
|
Configuration.default do |config|
|
data/spec/spec_helper.rb
CHANGED
|
@@ -21,7 +21,8 @@ USER_AGENTS = {
|
|
|
21
21
|
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",
|
|
22
22
|
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",
|
|
23
23
|
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",
|
|
24
|
-
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
|
+
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",
|
|
25
|
+
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
|
}
|
|
26
27
|
|
|
27
28
|
def expect_default_values(hash)
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: secure_headers
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.6.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Neil Matatall
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2017-03-03 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rake
|
|
@@ -58,9 +58,16 @@ files:
|
|
|
58
58
|
- LICENSE
|
|
59
59
|
- README.md
|
|
60
60
|
- Rakefile
|
|
61
|
+
- docs/HPKP.md
|
|
62
|
+
- docs/cookies.md
|
|
63
|
+
- docs/hashes.md
|
|
64
|
+
- docs/named_overrides_and_appends.md
|
|
65
|
+
- docs/per_action_configuration.md
|
|
66
|
+
- docs/sinatra.md
|
|
61
67
|
- lib/secure_headers.rb
|
|
62
68
|
- lib/secure_headers/configuration.rb
|
|
63
69
|
- lib/secure_headers/hash_helper.rb
|
|
70
|
+
- lib/secure_headers/headers/clear_site_data.rb
|
|
64
71
|
- lib/secure_headers/headers/content_security_policy.rb
|
|
65
72
|
- lib/secure_headers/headers/content_security_policy_config.rb
|
|
66
73
|
- lib/secure_headers/headers/cookie.rb
|
|
@@ -80,6 +87,7 @@ files:
|
|
|
80
87
|
- lib/tasks/tasks.rake
|
|
81
88
|
- secure_headers.gemspec
|
|
82
89
|
- spec/lib/secure_headers/configuration_spec.rb
|
|
90
|
+
- spec/lib/secure_headers/headers/clear_site_data_spec.rb
|
|
83
91
|
- spec/lib/secure_headers/headers/content_security_policy_spec.rb
|
|
84
92
|
- spec/lib/secure_headers/headers/cookie_spec.rb
|
|
85
93
|
- spec/lib/secure_headers/headers/policy_management_spec.rb
|
|
@@ -111,18 +119,19 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
111
119
|
version: '0'
|
|
112
120
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
113
121
|
requirements:
|
|
114
|
-
- - "
|
|
122
|
+
- - ">="
|
|
115
123
|
- !ruby/object:Gem::Version
|
|
116
|
-
version:
|
|
124
|
+
version: '0'
|
|
117
125
|
requirements: []
|
|
118
126
|
rubyforge_project:
|
|
119
|
-
rubygems_version: 2.
|
|
127
|
+
rubygems_version: 2.5.2
|
|
120
128
|
signing_key:
|
|
121
129
|
specification_version: 4
|
|
122
130
|
summary: Add easily configured security headers to responses including content-security-policy,
|
|
123
131
|
x-frame-options, strict-transport-security, etc.
|
|
124
132
|
test_files:
|
|
125
133
|
- spec/lib/secure_headers/configuration_spec.rb
|
|
134
|
+
- spec/lib/secure_headers/headers/clear_site_data_spec.rb
|
|
126
135
|
- spec/lib/secure_headers/headers/content_security_policy_spec.rb
|
|
127
136
|
- spec/lib/secure_headers/headers/cookie_spec.rb
|
|
128
137
|
- spec/lib/secure_headers/headers/policy_management_spec.rb
|