secure_headers 2.2.4 → 2.3.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.
Potentially problematic release.
This version of secure_headers might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/README.md +30 -0
- data/lib/secure_headers/headers/content_security_policy.rb +2 -0
- data/lib/secure_headers/headers/public_key_pins.rb +1 -0
- data/lib/secure_headers/headers/strict_transport_security.rb +1 -0
- data/lib/secure_headers/headers/x_content_type_options.rb +2 -1
- data/lib/secure_headers/headers/x_download_options.rb +1 -0
- data/lib/secure_headers/headers/x_frame_options.rb +1 -0
- data/lib/secure_headers/headers/x_permitted_cross_domain_policies.rb +1 -0
- data/lib/secure_headers/headers/x_xss_protection.rb +1 -0
- data/lib/secure_headers/version.rb +1 -1
- data/lib/secure_headers.rb +48 -20
- data/spec/lib/secure_headers_spec.rb +50 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2ea3335e72b8eaea53c9fc03a77c008b73fc674c
|
4
|
+
data.tar.gz: 4097b301e8e7f18174abda1c6412f9652cd4c39a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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)
|
@@ -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
|
data/lib/secure_headers.rb
CHANGED
@@ -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
|
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.
|
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-
|
11
|
+
date: 2015-09-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|