secure_headers 3.2.0 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of secure_headers might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a02f16867ec55f8c168ace664cc63d760785256f
4
- data.tar.gz: db54c113af8919984c8f382b957834f38210cf3e
3
+ metadata.gz: c3acd5dfb3fc3a7c4037ef42b72765a4f1b34ede
4
+ data.tar.gz: 98f0ce842bac69bf7c5f4d3d4cc19e4281ebe00e
5
5
  SHA512:
6
- metadata.gz: 6d9ddcb98a8c646d4e7a8cdb79bf3d8638cae4cb230ff268660e8eab7000fba99bb65e126ce55b3ff5f2a0346013fcf8b769dab4db697c82ab4461d444d0e2bd
7
- data.tar.gz: b63c79ac3e9b37a4cff698f979f1ca6fd7e92567e35b1f9026be2e68a205e5badff302d512938a4d36517e8ec5b752d4833082e1b733ff73916fbf0b326641aa
6
+ metadata.gz: 75d3b9033b09f0ac40675e8e8706185d9c0ca465a38f857228bf56857f5f44ba1eab5559b9c9f64f34ee398226ccd9dda5e26923f5325dcadd7be8ff0a957314
7
+ data.tar.gz: f6ffb2babf72009e60a4d4663ee6e933db8f8acb7159021e66a07168e1c6743df621309fb63e884f3257217d28951b196b2a192739860ce459f4fbabbab35622
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## 3.3.0 referrer-policy support
2
+
3
+ While not officially part of the spec and not implemented anywhere, support for the experimental [`referrer-policy` header](https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-header) was [preemptively added](https://github.com/twitter/secureheaders/pull/249).
4
+
5
+ Additionally, two minor enhancements were added this version:
6
+ 1. [Warn when the HPKP report host is the same as the current host](https://github.com/twitter/secureheaders/pull/246). By definition any generated reports would be reporting to a known compromised connection.
7
+ 1. [Filter unsupported CSP directives when using Edge](https://github.com/twitter/secureheaders/pull/247). Previously, this was causing many warnings in the developer console.
8
+
1
9
  ## 3.2.0 Cookie settings and CSP hash sources
2
10
 
3
11
  ### Cookies
@@ -114,6 +122,7 @@ console.log(1)
114
122
  Content-Security-Policy: ...
115
123
  script-src 'sha256-yktKiAsZWmc8WpOyhnmhQoDf9G2dAZvuBBC+V0LGQhg=' ... ;
116
124
  style-src 'sha256-SLp6LO3rrKDJwsG9uJUxZapb4Wp2Zhj6Bu3l+d9rnAY=' 'sha256-HSGHqlRoKmHAGTAJ2Rq0piXX4CnEbOl1ArNd6ejp2TE=' ...;
125
+ ```
117
126
 
118
127
  ## 3.1.2 Bug fix for regression
119
128
 
data/README.md CHANGED
@@ -13,6 +13,7 @@ The gem will automatically apply several headers that are related to security.
13
13
  - X-Content-Type-Options - [Prevent content type sniffing](https://msdn.microsoft.com/library/gg622941\(v=vs.85\).aspx)
14
14
  - X-Download-Options - [Prevent file downloads opening](https://msdn.microsoft.com/library/jj542450(v=vs.85).aspx)
15
15
  - X-Permitted-Cross-Domain-Policies - [Restrict Adobe Flash Player's access to data](https://www.adobe.com/devnet/adobe-media-server/articles/cross-domain-xml-for-streaming.html)
16
+ - Referrer-Policy - [Referrer Policy draft](https://w3c.github.io/webappsec-referrer-policy/)
16
17
  - Public Key Pinning - Pin certificate fingerprints in the browser to prevent man-in-the-middle attacks due to compromised Certificate Authorities. [Public Key Pinning Specification](https://tools.ietf.org/html/rfc7469)
17
18
 
18
19
  It can also mark all http cookies with the Secure, HttpOnly and SameSite attributes (when configured to do so).
@@ -44,6 +45,7 @@ SecureHeaders::Configuration.default do |config|
44
45
  config.x_xss_protection = "1; mode=block"
45
46
  config.x_download_options = "noopen"
46
47
  config.x_permitted_cross_domain_policies = "none"
48
+ config.referrer_policy = "origin-when-cross-origin"
47
49
  config.csp = {
48
50
  # "meta" values. these will shaped the header, but the values are not included in the header.
49
51
  report_only: true, # default: false
@@ -330,9 +332,7 @@ config.hpkp = {
330
332
  {sha256: '73a2c64f9545172c1195efb6616ca5f7afd1df6f245407cafb90de3998a1c97f'}
331
333
  ],
332
334
  report_only: true, # defaults to false (report-only mode)
333
- report_uri: 'https://report-uri.io/example-hpkp',
334
- app_name: 'example',
335
- tag_report_uri: true
335
+ report_uri: 'https://report-uri.io/example-hpkp'
336
336
  }
337
337
  ```
338
338
 
@@ -61,6 +61,7 @@ module SecureHeaders
61
61
  config.validate_config!
62
62
  @configurations ||= {}
63
63
  config.send(:cache_headers!)
64
+ config.send(:cache_hpkp_report_host)
64
65
  config.freeze
65
66
  @configurations[name] = config
66
67
  end
@@ -102,11 +103,13 @@ module SecureHeaders
102
103
  end
103
104
  end
104
105
 
106
+ attr_accessor :dynamic_csp
107
+
105
108
  attr_writer :hsts, :x_frame_options, :x_content_type_options,
106
109
  :x_xss_protection, :x_download_options, :x_permitted_cross_domain_policies,
107
- :hpkp, :dynamic_csp, :cookies
110
+ :referrer_policy
108
111
 
109
- attr_reader :cached_headers, :csp, :dynamic_csp, :cookies
112
+ attr_reader :cached_headers, :csp, :cookies, :hpkp, :hpkp_report_host
110
113
 
111
114
  HASH_CONFIG_FILE = ENV["secure_headers_generated_hashes_file"] || "config/secure_headers_generated_hashes.yml"
112
115
  if File.exists?(HASH_CONFIG_FILE)
@@ -117,6 +120,7 @@ module SecureHeaders
117
120
 
118
121
  def initialize(&block)
119
122
  self.hpkp = OPT_OUT
123
+ self.referrer_policy = OPT_OUT
120
124
  self.csp = self.class.send(:deep_copy, CSP::DEFAULT_CONFIG)
121
125
  instance_eval &block if block_given?
122
126
  end
@@ -136,7 +140,9 @@ module SecureHeaders
136
140
  copy.x_xss_protection = @x_xss_protection
137
141
  copy.x_download_options = @x_download_options
138
142
  copy.x_permitted_cross_domain_policies = @x_permitted_cross_domain_policies
143
+ copy.referrer_policy = @referrer_policy
139
144
  copy.hpkp = @hpkp
145
+ copy.hpkp_report_host = @hpkp_report_host
140
146
  copy
141
147
  end
142
148
 
@@ -175,6 +181,7 @@ module SecureHeaders
175
181
  def validate_config!
176
182
  StrictTransportSecurity.validate_config!(@hsts)
177
183
  ContentSecurityPolicy.validate_config!(@csp)
184
+ ReferrerPolicy.validate_config!(@referrer_policy)
178
185
  XFrameOptions.validate_config!(@x_frame_options)
179
186
  XContentTypeOptions.validate_config!(@x_content_type_options)
180
187
  XXssProtection.validate_config!(@x_xss_protection)
@@ -199,12 +206,32 @@ module SecureHeaders
199
206
  @csp = new_csp
200
207
  end
201
208
 
209
+ def cookies=(cookies)
210
+ @cookies = cookies
211
+ end
212
+
202
213
  def cached_headers=(headers)
203
214
  @cached_headers = headers
204
215
  end
205
216
 
217
+ def hpkp=(hpkp)
218
+ @hpkp = hpkp
219
+ end
220
+
221
+ def hpkp_report_host=(hpkp_report_host)
222
+ @hpkp_report_host = hpkp_report_host
223
+ end
224
+
206
225
  private
207
226
 
227
+ def cache_hpkp_report_host
228
+ has_report_uri = @hpkp && @hpkp != OPT_OUT && @hpkp[:report_uri]
229
+ self.hpkp_report_host = if has_report_uri
230
+ parsed_report_uri = URI.parse(@hpkp[:report_uri])
231
+ parsed_report_uri.host
232
+ end
233
+ end
234
+
208
235
  # Public: Precompute the header names and values for this configuraiton.
209
236
  # Ensures that headers generated at configure time, not on demand.
210
237
  #
@@ -91,6 +91,7 @@ module SecureHeaders
91
91
  UPGRADE_INSECURE_REQUESTS
92
92
  ].freeze
93
93
 
94
+ EDGE_DIRECTIVES = DIRECTIVES_1_0
94
95
  SAFARI_DIRECTIVES = DIRECTIVES_1_0
95
96
 
96
97
  FIREFOX_UNSUPPORTED_DIRECTIVES = [
@@ -118,6 +119,7 @@ module SecureHeaders
118
119
  "Opera" => CHROME_DIRECTIVES,
119
120
  "Firefox" => FIREFOX_DIRECTIVES,
120
121
  "Safari" => SAFARI_DIRECTIVES,
122
+ "Edge" => EDGE_DIRECTIVES,
121
123
  "Other" => CHROME_DIRECTIVES
122
124
  }.freeze
123
125
 
@@ -0,0 +1,33 @@
1
+ module SecureHeaders
2
+ class ReferrerPolicyConfigError < StandardError; end
3
+ class ReferrerPolicy
4
+ HEADER_NAME = "Referrer-Policy"
5
+ DEFAULT_VALUE = "origin-when-cross-origin"
6
+ VALID_POLICIES = %w(
7
+ no-referrer
8
+ no-referrer-when-downgrade
9
+ origin
10
+ origin-when-cross-origin
11
+ unsafe-url
12
+ )
13
+ CONFIG_KEY = :referrer_policy
14
+
15
+ class << self
16
+ # Public: generate an Referrer Policy header.
17
+ #
18
+ # Returns a default header if no configuration is provided, or a
19
+ # header name and value based on the config.
20
+ def make_header(config = nil)
21
+ [HEADER_NAME, config || DEFAULT_VALUE]
22
+ end
23
+
24
+ def validate_config!(config)
25
+ return if config.nil? || config == OPT_OUT
26
+ raise TypeError.new("Must be a string. Found #{config.class}: #{config}") unless config.is_a?(String)
27
+ unless VALID_POLICIES.include?(config.downcase)
28
+ raise ReferrerPolicyConfigError.new("Value can only be one of #{VALID_POLICIES.join(', ')}")
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -1,5 +1,7 @@
1
1
  module SecureHeaders
2
2
  class Middleware
3
+ HPKP_SAME_HOST_WARNING = "[WARNING] HPKP report host should not be the same as the request host. See https://github.com/twitter/secureheaders/issues/166"
4
+
3
5
  def initialize(app)
4
6
  @app = app
5
7
  end
@@ -10,6 +12,10 @@ module SecureHeaders
10
12
  status, headers, response = @app.call(env)
11
13
 
12
14
  config = SecureHeaders.config_for(req)
15
+ if config.hpkp_report_host == req.host
16
+ Kernel.warn(HPKP_SAME_HOST_WARNING)
17
+ end
18
+
13
19
  flag_cookies!(headers, override_secure(env, config.cookies)) if config.cookies
14
20
  headers.merge!(SecureHeaders.header_hash_for(req))
15
21
  [status, headers, response]
@@ -7,7 +7,7 @@ if defined?(Rails::Railtie)
7
7
  'X-Permitted-Cross-Domain-Policies', 'X-Download-Options',
8
8
  'X-Content-Type-Options', 'Strict-Transport-Security',
9
9
  'Content-Security-Policy', 'Content-Security-Policy-Report-Only',
10
- 'Public-Key-Pins', 'Public-Key-Pins-Report-Only']
10
+ 'Public-Key-Pins', 'Public-Key-Pins-Report-Only', 'Referrer-Policy']
11
11
 
12
12
  initializer "secure_headers.middleware" do
13
13
  Rails.application.config.middleware.insert_before 0, SecureHeaders::Middleware
@@ -9,6 +9,7 @@ require "secure_headers/headers/x_xss_protection"
9
9
  require "secure_headers/headers/x_content_type_options"
10
10
  require "secure_headers/headers/x_download_options"
11
11
  require "secure_headers/headers/x_permitted_cross_domain_policies"
12
+ require "secure_headers/headers/referrer_policy"
12
13
  require "secure_headers/middleware"
13
14
  require "secure_headers/railtie"
14
15
  require "secure_headers/view_helper"
@@ -27,6 +28,7 @@ module SecureHeaders
27
28
  ContentSecurityPolicy,
28
29
  StrictTransportSecurity,
29
30
  PublicKeyPins,
31
+ ReferrerPolicy,
30
32
  XContentTypeOptions,
31
33
  XDownloadOptions,
32
34
  XFrameOptions,
@@ -1,7 +1,7 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  Gem::Specification.new do |gem|
3
3
  gem.name = "secure_headers"
4
- gem.version = "3.2.0"
4
+ gem.version = "3.3.0"
5
5
  gem.authors = ["Neil Matatall"]
6
6
  gem.email = ["neil.matatall@gmail.com"]
7
7
  gem.description = 'Security related headers all in one gem.'
@@ -104,6 +104,11 @@ module SecureHeaders
104
104
  expect(policy.value).to eq("default-src 'self'; base-uri 'self'; connect-src 'self'; font-src 'self'; form-action 'self'; frame-ancestors 'self'; frame-src 'self'; img-src 'self'; media-src 'self'; object-src 'self'; sandbox 'self'; script-src 'self' 'nonce-123456'; style-src 'self'; upgrade-insecure-requests; report-uri 'self'")
105
105
  end
106
106
 
107
+ it "adds 'unsafe-inline', filters base-uri, blocked-all-mixed-content, upgrade-insecure-requests, child-src, form-action, frame-ancestors, nonce sources, hash sources, and plugin-types for Edge" do
108
+ policy = ContentSecurityPolicy.new(complex_opts, USER_AGENTS[:edge])
109
+ expect(policy.value).to eq("default-src 'self'; connect-src 'self'; font-src 'self'; frame-src 'self'; img-src 'self'; media-src 'self'; object-src 'self'; sandbox 'self'; script-src 'self' 'unsafe-inline'; style-src 'self'; report-uri 'self'")
110
+ end
111
+
107
112
  it "adds 'unsafe-inline', filters base-uri, blocked-all-mixed-content, upgrade-insecure-requests, child-src, form-action, frame-ancestors, nonce sources, hash sources, and plugin-types for safari" do
108
113
  policy = ContentSecurityPolicy.new(complex_opts, USER_AGENTS[:safari6])
109
114
  expect(policy.value).to eq("default-src 'self'; connect-src 'self'; font-src 'self'; frame-src 'self'; img-src 'self'; media-src 'self'; object-src 'self'; sandbox 'self'; script-src 'self' 'unsafe-inline'; style-src 'self'; report-uri 'self'")
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+ module SecureHeaders
4
+ describe ReferrerPolicy do
5
+ specify { expect(ReferrerPolicy.make_header).to eq([ReferrerPolicy::HEADER_NAME, "origin-when-cross-origin"]) }
6
+ specify { expect(ReferrerPolicy.make_header('no-referrer')).to eq([ReferrerPolicy::HEADER_NAME, "no-referrer"]) }
7
+
8
+ context "valid configuration values" do
9
+ it "accepts 'no-referrer'" do
10
+ expect do
11
+ ReferrerPolicy.validate_config!("no-referrer")
12
+ end.not_to raise_error
13
+ end
14
+
15
+ it "accepts 'no-referrer-when-downgrade'" do
16
+ expect do
17
+ ReferrerPolicy.validate_config!("no-referrer-when-downgrade")
18
+ end.not_to raise_error
19
+ end
20
+
21
+ it "accepts 'origin'" do
22
+ expect do
23
+ ReferrerPolicy.validate_config!("origin")
24
+ end.not_to raise_error
25
+ end
26
+
27
+ it "accepts 'origin-when-cross-origin'" do
28
+ expect do
29
+ ReferrerPolicy.validate_config!("origin-when-cross-origin")
30
+ end.not_to raise_error
31
+ end
32
+
33
+ it "accepts 'unsafe-url'" do
34
+ expect do
35
+ ReferrerPolicy.validate_config!("unsafe-url")
36
+ end.not_to raise_error
37
+ end
38
+
39
+ it "accepts nil" do
40
+ expect do
41
+ ReferrerPolicy.validate_config!(nil)
42
+ end.not_to raise_error
43
+ end
44
+ end
45
+
46
+ context 'invlaid configuration values' do
47
+ it "doesn't accept invalid values" do
48
+ expect do
49
+ ReferrerPolicy.validate_config!("open")
50
+ end.to raise_error(ReferrerPolicyConfigError)
51
+ end
52
+ end
53
+ end
54
+ end
@@ -13,6 +13,24 @@ module SecureHeaders
13
13
  Configuration.default
14
14
  end
15
15
 
16
+ it "warns if the hpkp report-uri host is the same as the current host" do
17
+ report_host = "report-uri.io"
18
+ Configuration.default do |config|
19
+ config.hpkp = {
20
+ max_age: 10000000,
21
+ pins: [
22
+ {sha256: 'b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c'},
23
+ {sha256: '73a2c64f9545172c1195efb6616ca5f7afd1df6f245407cafb90de3998a1c97f'}
24
+ ],
25
+ report_uri: "https://#{report_host}/example-hpkp"
26
+ }
27
+ end
28
+
29
+ expect(Kernel).to receive(:warn).with(Middleware::HPKP_SAME_HOST_WARNING)
30
+
31
+ middleware.call(Rack::MockRequest.env_for("https://#{report_host}", {}))
32
+ end
33
+
16
34
  it "sets the headers" do
17
35
  _, env = middleware.call(Rack::MockRequest.env_for("https://looocalhost", {}))
18
36
  expect_default_values(env)
@@ -20,6 +20,13 @@ module SecureHeaders
20
20
  end.to raise_error(Configuration::NotYetConfiguredError)
21
21
  end
22
22
 
23
+ it "raises and ArgumentError when referencing an override that has not been set" do
24
+ expect do
25
+ Configuration.default
26
+ SecureHeaders.use_secure_headers_override(request, :missing)
27
+ end.to raise_error(ArgumentError)
28
+ end
29
+
23
30
  describe "#header_hash_for" do
24
31
  it "allows you to opt out of individual headers via API" do
25
32
  Configuration.default
@@ -305,6 +312,14 @@ module SecureHeaders
305
312
  end.to raise_error(XPCDPConfigError)
306
313
  end
307
314
 
315
+ it "validates your referrer_policy config upon configuration" do
316
+ expect do
317
+ Configuration.default do |config|
318
+ config.referrer_policy = "lol"
319
+ end
320
+ end.to raise_error(ReferrerPolicyConfigError)
321
+ end
322
+
308
323
  it "validates your hpkp config upon configuration" do
309
324
  expect do
310
325
  Configuration.default do |config|
@@ -312,6 +327,14 @@ module SecureHeaders
312
327
  end
313
328
  end.to raise_error(PublicKeyPinsConfigError)
314
329
  end
330
+
331
+ it "validates your cookies config upon configuration" do
332
+ expect do
333
+ Configuration.default do |config|
334
+ config.cookies = { secure: "lol" }
335
+ end
336
+ end.to raise_error(CookiesConfigError)
337
+ end
315
338
  end
316
339
  end
317
340
  end
data/spec/spec_helper.rb CHANGED
@@ -11,6 +11,7 @@ require File.join(File.dirname(__FILE__), '..', 'lib', 'secure_headers')
11
11
 
12
12
 
13
13
  USER_AGENTS = {
14
+ 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
15
  firefox: 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:14.0) Gecko/20100101 Firefox/14.0.1',
15
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',
16
17
  ie: 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/5.0)',
@@ -30,6 +31,7 @@ def expect_default_values(hash)
30
31
  expect(hash[SecureHeaders::XXssProtection::HEADER_NAME]).to eq(SecureHeaders::XXssProtection::DEFAULT_VALUE)
31
32
  expect(hash[SecureHeaders::XContentTypeOptions::HEADER_NAME]).to eq(SecureHeaders::XContentTypeOptions::DEFAULT_VALUE)
32
33
  expect(hash[SecureHeaders::XPermittedCrossDomainPolicies::HEADER_NAME]).to eq(SecureHeaders::XPermittedCrossDomainPolicies::DEFAULT_VALUE)
34
+ expect(hash[SecureHeaders::ReferrerPolicy::HEADER_NAME]).to be_nil
33
35
  end
34
36
 
35
37
  module SecureHeaders
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.2.0
4
+ version: 3.3.0
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-04-18 00:00:00.000000000 Z
11
+ date: 2016-04-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -63,6 +63,7 @@ files:
63
63
  - lib/secure_headers/headers/cookie.rb
64
64
  - lib/secure_headers/headers/policy_management.rb
65
65
  - lib/secure_headers/headers/public_key_pins.rb
66
+ - lib/secure_headers/headers/referrer_policy.rb
66
67
  - lib/secure_headers/headers/strict_transport_security.rb
67
68
  - lib/secure_headers/headers/x_content_type_options.rb
68
69
  - lib/secure_headers/headers/x_download_options.rb
@@ -80,6 +81,7 @@ files:
80
81
  - spec/lib/secure_headers/headers/cookie_spec.rb
81
82
  - spec/lib/secure_headers/headers/policy_management_spec.rb
82
83
  - spec/lib/secure_headers/headers/public_key_pins_spec.rb
84
+ - spec/lib/secure_headers/headers/referrer_policy_spec.rb
83
85
  - spec/lib/secure_headers/headers/strict_transport_security_spec.rb
84
86
  - spec/lib/secure_headers/headers/x_content_type_options_spec.rb
85
87
  - spec/lib/secure_headers/headers/x_download_options_spec.rb
@@ -122,6 +124,7 @@ test_files:
122
124
  - spec/lib/secure_headers/headers/cookie_spec.rb
123
125
  - spec/lib/secure_headers/headers/policy_management_spec.rb
124
126
  - spec/lib/secure_headers/headers/public_key_pins_spec.rb
127
+ - spec/lib/secure_headers/headers/referrer_policy_spec.rb
125
128
  - spec/lib/secure_headers/headers/strict_transport_security_spec.rb
126
129
  - spec/lib/secure_headers/headers/x_content_type_options_spec.rb
127
130
  - spec/lib/secure_headers/headers/x_download_options_spec.rb