secure_headers 2.2.4 → 2.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: 8a0931db8855224044856cad01f2226dfb325c93
4
- data.tar.gz: bc3520f802677b2c7967d9e7ae928c5d6ef4d2ca
3
+ metadata.gz: 2ea3335e72b8eaea53c9fc03a77c008b73fc674c
4
+ data.tar.gz: 4097b301e8e7f18174abda1c6412f9652cd4c39a
5
5
  SHA512:
6
- metadata.gz: 41b4ee3848c1261162c5a5e7f80931a1e7891a08ac0d1f49b5ebfae5ae819f0e8a5b3577499d4cd8d62eaf71d36218bb7bf97cd263d220a67a72e14c8a49dac6
7
- data.tar.gz: acae6ac54a26a925e3fd74a2b24c50a00349cce8be8d9dca8d81ee1dbae68008defa925bb3a10f99996476687de0b632fca07cfc6d40bd7511dd8acc1cc7a0c1
6
+ metadata.gz: 53db0ad5f6d9e7a85bde9aa167a927e3bda91351ce2f57af0f505d1b6c0856ca50b295ad87e26c1b25fa0142a95d8ef8b11f12f562377e60a0b398454abdd5b9
7
+ data.tar.gz: a6c3c2366fcf08ed3749f6c6e9146e2fbc33fb167a504404e195bd9813c709b0d497c2c2fc64f138a482a5fcc68eb4d212895761722ae0beed4b49ccea481e81
data/README.md CHANGED
@@ -415,8 +415,38 @@ def before_load
415
415
  end
416
416
  ```
417
417
 
418
+ ### Using in rack middleware
419
+
420
+ The `SecureHeaders::header_hash` generates a hash of all header values, which is useful for merging with rack middleware values.
421
+
422
+ ```ruby
423
+ class MySecureHeaders
424
+ include SecureHeaders
425
+ def initialize(app)
426
+ @app = app
427
+ end
428
+
429
+ def call(env)
430
+ status, headers, response = @app.call(env)
431
+ security_headers = if override?
432
+ SecureHeaders::header_hash(:csp => false) # uses global config, but overrides CSP config
433
+ else
434
+ SecureHeaders::header_hash # uses global config
435
+ end
436
+ [status, headers.merge(security_headers), [response.body]]
437
+ end
438
+ end
439
+
440
+ module Testapp
441
+ class Application < Rails::Application
442
+ config.middleware.use MySecureHeaders
443
+ end
444
+ end
445
+ ```
446
+
418
447
  ## Similar libraries
419
448
 
449
+ * Rack [rack-secure_headers](https://github.com/harmoni/rack-secure_headers)
420
450
  * Node.js (express) [helmet](https://github.com/evilpacket/helmet) and [hood](https://github.com/seanmonstar/hood)
421
451
  * Node.js (hapi) [blankie](https://github.com/nlf/blankie)
422
452
  * J2EE Servlet >= 3.0 [headlines](https://github.com/sourceclear/headlines)
@@ -40,7 +40,9 @@ module SecureHeaders
40
40
  SOURCE_DIRECTIVES = DIRECTIVES + NON_DEFAULT_SOURCES
41
41
 
42
42
  ALL_DIRECTIVES = DIRECTIVES + NON_DEFAULT_SOURCES + OTHER
43
+ CONFIG_KEY = :csp
43
44
  end
45
+
44
46
  include Constants
45
47
 
46
48
  attr_reader :disable_fill_missing, :ssl_request
@@ -6,6 +6,7 @@ module SecureHeaders
6
6
  ENV_KEY = 'secure_headers.public_key_pins'
7
7
  HASH_ALGORITHMS = [:sha256]
8
8
  DIRECTIVES = [:max_age]
9
+ CONFIG_KEY = :hpkp
9
10
  end
10
11
  class << self
11
12
  def symbol_to_hyphen_case sym
@@ -8,6 +8,7 @@ module SecureHeaders
8
8
  DEFAULT_VALUE = "max-age=" + HSTS_MAX_AGE
9
9
  VALID_STS_HEADER = /\Amax-age=\d+(; includeSubdomains)?(; preload)?\z/i
10
10
  MESSAGE = "The config value supplied for the HSTS header was invalid."
11
+ CONFIG_KEY = :hsts
11
12
  end
12
13
  include Constants
13
14
 
@@ -5,6 +5,7 @@ module SecureHeaders
5
5
  module Constants
6
6
  X_CONTENT_TYPE_OPTIONS_HEADER_NAME = "X-Content-Type-Options"
7
7
  DEFAULT_VALUE = "nosniff"
8
+ CONFIG_KEY = :x_content_type_options
8
9
  end
9
10
  include Constants
10
11
 
@@ -37,4 +38,4 @@ module SecureHeaders
37
38
  end
38
39
  end
39
40
  end
40
- end
41
+ end
@@ -4,6 +4,7 @@ module SecureHeaders
4
4
  module Constants
5
5
  XDO_HEADER_NAME = "X-Download-Options"
6
6
  DEFAULT_VALUE = 'noopen'
7
+ CONFIG_KEY = :x_download_options
7
8
  end
8
9
  include Constants
9
10
 
@@ -5,6 +5,7 @@ module SecureHeaders
5
5
  XFO_HEADER_NAME = "X-Frame-Options"
6
6
  DEFAULT_VALUE = 'SAMEORIGIN'
7
7
  VALID_XFO_HEADER = /\A(SAMEORIGIN\z|DENY\z|ALLOW-FROM[:\s])/i
8
+ CONFIG_KEY = :x_frame_options
8
9
  end
9
10
  include Constants
10
11
 
@@ -5,6 +5,7 @@ module SecureHeaders
5
5
  XPCDP_HEADER_NAME = "X-Permitted-Cross-Domain-Policies"
6
6
  DEFAULT_VALUE = 'none'
7
7
  VALID_POLICIES = %w(all none master-only by-content-type by-ftp-filename)
8
+ CONFIG_KEY = :x_permitted_cross_domain_policies
8
9
  end
9
10
  include Constants
10
11
 
@@ -5,6 +5,7 @@ module SecureHeaders
5
5
  X_XSS_PROTECTION_HEADER_NAME = 'X-XSS-Protection'
6
6
  DEFAULT_VALUE = "1"
7
7
  VALID_X_XSS_HEADER = /\A[01](; mode=block)?(; report=.*)?\z/i
8
+ CONFIG_KEY = :x_xss_protection
8
9
  end
9
10
  include Constants
10
11
 
@@ -1,3 +1,3 @@
1
1
  module SecureHeaders
2
- VERSION = "2.2.4"
2
+ VERSION = "2.3.0"
3
3
  end
@@ -1,7 +1,32 @@
1
+ require "secure_headers/version"
2
+ require "secure_headers/header"
3
+ require "secure_headers/headers/public_key_pins"
4
+ require "secure_headers/headers/content_security_policy"
5
+ require "secure_headers/headers/x_frame_options"
6
+ require "secure_headers/headers/strict_transport_security"
7
+ require "secure_headers/headers/x_xss_protection"
8
+ require "secure_headers/headers/x_content_type_options"
9
+ require "secure_headers/headers/x_download_options"
10
+ require "secure_headers/headers/x_permitted_cross_domain_policies"
11
+ require "secure_headers/railtie"
12
+ require "secure_headers/hash_helper"
13
+ require "secure_headers/view_helper"
14
+
1
15
  module SecureHeaders
2
16
  SCRIPT_HASH_CONFIG_FILE = 'config/script_hashes.yml'
3
17
  HASHES_ENV_KEY = 'secure_headers.script_hashes'
4
18
 
19
+ ALL_HEADER_CLASSES = [
20
+ SecureHeaders::ContentSecurityPolicy,
21
+ SecureHeaders::StrictTransportSecurity,
22
+ SecureHeaders::PublicKeyPins,
23
+ SecureHeaders::XContentTypeOptions,
24
+ SecureHeaders::XDownloadOptions,
25
+ SecureHeaders::XFrameOptions,
26
+ SecureHeaders::XPermittedCrossDomainPolicies,
27
+ SecureHeaders::XXssProtection
28
+ ]
29
+
5
30
  module Configuration
6
31
  class << self
7
32
  attr_accessor :hsts, :x_frame_options, :x_content_type_options,
@@ -24,6 +49,27 @@ module SecureHeaders
24
49
  include InstanceMethods
25
50
  end
26
51
  end
52
+
53
+ def header_hash(options = nil)
54
+ ALL_HEADER_CLASSES.inject({}) do |memo, klass|
55
+ config = if options.is_a?(Hash) && options[klass::Constants::CONFIG_KEY]
56
+ options[klass::Constants::CONFIG_KEY]
57
+ else
58
+ ::SecureHeaders::Configuration.send(klass::Constants::CONFIG_KEY)
59
+ end
60
+
61
+ unless klass == SecureHeaders::PublicKeyPins && !config.is_a?(Hash)
62
+ header = get_a_header(klass::Constants::CONFIG_KEY, klass, config)
63
+ memo[header.name] = header.value
64
+ end
65
+ memo
66
+ end
67
+ end
68
+
69
+ def get_a_header(name, klass, options)
70
+ return if options == false
71
+ klass.new(options)
72
+ end
27
73
  end
28
74
 
29
75
  module ClassMethods
@@ -161,13 +207,10 @@ module SecureHeaders
161
207
  options.nil? ? ::SecureHeaders::Configuration.send(type) : options
162
208
  end
163
209
 
164
-
165
210
  def set_a_header(name, klass, options=nil)
166
- options = secure_header_options_for name, options
211
+ options = secure_header_options_for(name, options)
167
212
  return if options == false
168
-
169
- header = klass.new(options)
170
- set_header(header)
213
+ set_header(SecureHeaders::get_a_header(name, klass, options))
171
214
  end
172
215
 
173
216
  def set_header(name_or_header, value=nil)
@@ -180,18 +223,3 @@ module SecureHeaders
180
223
  end
181
224
  end
182
225
  end
183
-
184
-
185
- require "secure_headers/version"
186
- require "secure_headers/header"
187
- require "secure_headers/headers/public_key_pins"
188
- require "secure_headers/headers/content_security_policy"
189
- require "secure_headers/headers/x_frame_options"
190
- require "secure_headers/headers/strict_transport_security"
191
- require "secure_headers/headers/x_xss_protection"
192
- require "secure_headers/headers/x_content_type_options"
193
- require "secure_headers/headers/x_download_options"
194
- require "secure_headers/headers/x_permitted_cross_domain_policies"
195
- require "secure_headers/railtie"
196
- require "secure_headers/hash_helper"
197
- require "secure_headers/view_helper"
@@ -159,6 +159,56 @@ describe SecureHeaders do
159
159
  end
160
160
  end
161
161
 
162
+ describe "SecureHeaders#header_hash" do
163
+ def expect_default_values(hash)
164
+ expect(hash[XFO_HEADER_NAME]).to eq(SecureHeaders::XFrameOptions::Constants::DEFAULT_VALUE)
165
+ expect(hash[XDO_HEADER_NAME]).to eq(SecureHeaders::XDownloadOptions::Constants::DEFAULT_VALUE)
166
+ expect(hash[HSTS_HEADER_NAME]).to eq(SecureHeaders::StrictTransportSecurity::Constants::DEFAULT_VALUE)
167
+ expect(hash[X_XSS_PROTECTION_HEADER_NAME]).to eq(SecureHeaders::XXssProtection::Constants::DEFAULT_VALUE)
168
+ expect(hash[X_CONTENT_TYPE_OPTIONS_HEADER_NAME]).to eq(SecureHeaders::XContentTypeOptions::Constants::DEFAULT_VALUE)
169
+ expect(hash[XPCDP_HEADER_NAME]).to eq(SecureHeaders::XPermittedCrossDomainPolicies::Constants::DEFAULT_VALUE)
170
+ end
171
+
172
+ it "produces a hash of headers given a hash as config" do
173
+ hash = SecureHeaders::header_hash(:csp => {:default_src => 'none', :img_src => "data:", :disable_fill_missing => true})
174
+ expect(hash['Content-Security-Policy-Report-Only']).to eq("default-src 'none'; img-src data:;")
175
+ expect_default_values(hash)
176
+ end
177
+
178
+ it "produces a hash with a mix of config values, override values, and default values" do
179
+ ::SecureHeaders::Configuration.configure do |config|
180
+ config.hsts = { :max_age => '123456'}
181
+ config.hpkp = {
182
+ :enforce => true,
183
+ :max_age => 1000000,
184
+ :include_subdomains => true,
185
+ :report_uri => '//example.com/uri-directive',
186
+ :pins => [
187
+ {:sha256 => 'abc'},
188
+ {:sha256 => '123'}
189
+ ]
190
+ }
191
+ end
192
+
193
+ hash = SecureHeaders::header_hash(:csp => {:default_src => 'none', :img_src => "data:", :disable_fill_missing => true})
194
+ ::SecureHeaders::Configuration.configure do |config|
195
+ config.hsts = nil
196
+ config.hpkp = nil
197
+ end
198
+
199
+ expect(hash['Content-Security-Policy-Report-Only']).to eq("default-src 'none'; img-src data:;")
200
+ expect(hash[XFO_HEADER_NAME]).to eq(SecureHeaders::XFrameOptions::Constants::DEFAULT_VALUE)
201
+ expect(hash[HSTS_HEADER_NAME]).to eq("max-age=123456")
202
+ expect(hash[HPKP_HEADER_NAME]).to eq(%{max-age=1000000; pin-sha256="abc"; pin-sha256="123"; report-uri="//example.com/uri-directive"; includeSubDomains})
203
+ end
204
+
205
+ it "produces a hash of headers with default config" do
206
+ hash = SecureHeaders::header_hash
207
+ expect(hash['Content-Security-Policy-Report-Only']).to eq(SecureHeaders::ContentSecurityPolicy::Constants::DEFAULT_CSP_HEADER)
208
+ expect_default_values(hash)
209
+ end
210
+ end
211
+
162
212
  describe "#set_x_frame_options_header" do
163
213
  it "sets the X-Frame-Options header" do
164
214
  should_assign_header(XFO_HEADER_NAME, SecureHeaders::XFrameOptions::Constants::DEFAULT_VALUE)
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: 2.2.4
4
+ version: 2.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: 2015-08-26 00:00:00.000000000 Z
11
+ date: 2015-09-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake