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.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/.travis.yml +2 -0
  4. data/CHANGELOG.md +20 -1
  5. data/Gemfile +1 -0
  6. data/LICENSE +4 -199
  7. data/README.md +37 -388
  8. data/docs/HPKP.md +17 -0
  9. data/docs/cookies.md +50 -0
  10. data/docs/hashes.md +64 -0
  11. data/docs/named_overrides_and_appends.md +107 -0
  12. data/docs/per_action_configuration.md +105 -0
  13. data/docs/sinatra.md +25 -0
  14. data/lib/secure_headers/configuration.rb +5 -3
  15. data/lib/secure_headers/headers/clear_site_data.rb +51 -0
  16. data/lib/secure_headers/headers/content_security_policy.rb +6 -2
  17. data/lib/secure_headers/headers/content_security_policy_config.rb +21 -12
  18. data/lib/secure_headers/headers/policy_management.rb +14 -2
  19. data/lib/secure_headers/headers/referrer_policy.rb +4 -1
  20. data/lib/secure_headers/headers/strict_transport_security.rb +1 -1
  21. data/lib/secure_headers/headers/x_content_type_options.rb +1 -1
  22. data/lib/secure_headers/headers/x_download_options.rb +1 -1
  23. data/lib/secure_headers/headers/x_frame_options.rb +1 -1
  24. data/lib/secure_headers/headers/x_permitted_cross_domain_policies.rb +1 -1
  25. data/lib/secure_headers/headers/x_xss_protection.rb +1 -1
  26. data/lib/secure_headers/view_helper.rb +8 -0
  27. data/lib/secure_headers.rb +4 -1
  28. data/secure_headers.gemspec +1 -1
  29. data/spec/lib/secure_headers/headers/clear_site_data_spec.rb +103 -0
  30. data/spec/lib/secure_headers/headers/content_security_policy_spec.rb +17 -0
  31. data/spec/lib/secure_headers/headers/referrer_policy_spec.rb +18 -0
  32. data/spec/lib/secure_headers/middleware_spec.rb +12 -0
  33. data/spec/lib/secure_headers/view_helpers_spec.rb +10 -0
  34. data/spec/lib/secure_headers_spec.rb +22 -0
  35. data/spec/spec_helper.rb +2 -1
  36. 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.5.0.pre
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: 2016-09-09 00:00:00.000000000 Z
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: 1.3.1
124
+ version: '0'
117
125
  requirements: []
118
126
  rubyforge_project:
119
- rubygems_version: 2.4.5.1
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