secure_headers 2.0.2 → 2.1.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 +7 -0
- data/.ruby-version +1 -1
- data/README.md +34 -2
- data/lib/secure_headers.rb +14 -1
- data/lib/secure_headers/headers/public_key_pins.rb +95 -0
- data/lib/secure_headers/version.rb +1 -1
- data/spec/lib/secure_headers/headers/public_key_pins_spec.rb +37 -0
- data/spec/lib/secure_headers_spec.rb +47 -0
- data/spec/spec_helper.rb +1 -0
- metadata +16 -17
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 16e634b2502cd5ee9d87fac9a9d2c6af9bc48fda
|
4
|
+
data.tar.gz: 1416e09703db75cdf25379a1273477f346080c72
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d1483f86c255f59593766bf3312d0085df5b59281c2daf426c16bf930c92c06ae17c17e07984be696b1719336e89ea7000e19948713b310354c749200e2debd6
|
7
|
+
data.tar.gz: eaf23b06c98757048b1516d87e429a23b5c70606db476f90eb042250bbd863bd1fddfdbcf12a6fce51e077a0ee3e6332cedcc041514de6a0ce55295d77a4bd65
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
2.1.6
|
data/README.md
CHANGED
@@ -8,6 +8,7 @@ The gem will automatically apply several headers that are related to security.
|
|
8
8
|
- X-Content-Type-Options - [Prevent content type sniffing](http://msdn.microsoft.com/en-us/library/ie/gg622941\(v=vs.85\).aspx)
|
9
9
|
- X-Download-Options - [Prevent file downloads opening](http://msdn.microsoft.com/en-us/library/ie/jj542450(v=vs.85).aspx)
|
10
10
|
- 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)
|
11
|
+
- Public Key Pinning - Pin certificate fingerprints in the browser to prevent man-in-the-middle attacks due to compromised Certificate Authorites. [Public Key Pinnning Specification](https://tools.ietf.org/html/draft-ietf-websec-key-pinning-21)
|
11
12
|
|
12
13
|
## Usage
|
13
14
|
|
@@ -21,6 +22,7 @@ The following methods are going to be called, unless they are provided in a `ski
|
|
21
22
|
|
22
23
|
* `:set_csp_header`
|
23
24
|
* `:set_hsts_header`
|
25
|
+
* `:set_hpkp_header`
|
24
26
|
* `:set_x_frame_options_header`
|
25
27
|
* `:set_x_xss_protection_header`
|
26
28
|
* `:set_x_content_type_options_header`
|
@@ -51,15 +53,24 @@ This gem makes a few assumptions about how you will use some features. For exam
|
|
51
53
|
:img_src => "https:",
|
52
54
|
:report_uri => '//example.com/uri-directive'
|
53
55
|
}
|
56
|
+
config.hpkp = {
|
57
|
+
:max_age => 60.days.to_i,
|
58
|
+
:include_subdomains => true,
|
59
|
+
:report_uri => '//example.com/uri-directive',
|
60
|
+
:pins => [
|
61
|
+
{:sha256 => 'abc'},
|
62
|
+
{:sha256 => '123'}
|
63
|
+
]
|
64
|
+
}
|
54
65
|
end
|
55
66
|
|
56
|
-
# and then
|
67
|
+
# and then include this in application_controller.rb
|
57
68
|
class ApplicationController < ActionController::Base
|
58
69
|
ensure_security_headers
|
59
70
|
end
|
60
71
|
```
|
61
72
|
|
62
|
-
Or
|
73
|
+
Or do the config as a parameter to `ensure_security_headers`
|
63
74
|
|
64
75
|
```ruby
|
65
76
|
ensure_security_headers(
|
@@ -298,6 +309,26 @@ console.log("will raise an exception if not in script_hashes.yml!")
|
|
298
309
|
<% end %>
|
299
310
|
```
|
300
311
|
|
312
|
+
### Public Key Pins
|
313
|
+
|
314
|
+
Be aware that pinning error reporting is governed by the same rules as everything else. If you have a pinning failure that tries to report back to the same origin, by definition this will not work.
|
315
|
+
|
316
|
+
```
|
317
|
+
config.hpkp = {
|
318
|
+
max_age: 60.days.to_i, # max_age is a required parameter
|
319
|
+
include_subdomains: true, # whether or not to apply pins to subdomains
|
320
|
+
# Per the spec, SHA256 hashes are the only currently supported format.
|
321
|
+
pins: [
|
322
|
+
{sha256: 'b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c'},
|
323
|
+
{sha256: '73a2c64f9545172c1195efb6616ca5f7afd1df6f245407cafb90de3998a1c97f'}
|
324
|
+
],
|
325
|
+
enforce: true, # defaults to false (report-only mode)
|
326
|
+
report_uri: '//example.com/uri-directive',
|
327
|
+
app_name: 'example',
|
328
|
+
tag_report_uri: true
|
329
|
+
}
|
330
|
+
```
|
331
|
+
|
301
332
|
### Using with Sinatra
|
302
333
|
|
303
334
|
Here's an example using SecureHeaders for Sinatra applications:
|
@@ -321,6 +352,7 @@ require 'secure_headers'
|
|
321
352
|
:img_src => "https: data:",
|
322
353
|
:frame_src => "https: http:.twimg.com http://itunes.apple.com"
|
323
354
|
}
|
355
|
+
config.hpkp = false
|
324
356
|
end
|
325
357
|
|
326
358
|
class Donkey < Sinatra::Application
|
data/lib/secure_headers.rb
CHANGED
@@ -6,7 +6,7 @@ module SecureHeaders
|
|
6
6
|
class << self
|
7
7
|
attr_accessor :hsts, :x_frame_options, :x_content_type_options,
|
8
8
|
:x_xss_protection, :csp, :x_download_options, :script_hashes,
|
9
|
-
:x_permitted_cross_domain_policies
|
9
|
+
:x_permitted_cross_domain_policies, :hpkp
|
10
10
|
|
11
11
|
def configure &block
|
12
12
|
instance_eval &block
|
@@ -42,6 +42,7 @@ module SecureHeaders
|
|
42
42
|
self.secure_headers_options = options
|
43
43
|
before_filter :prep_script_hash
|
44
44
|
before_filter :set_hsts_header
|
45
|
+
before_filter :set_hpkp_header
|
45
46
|
before_filter :set_x_frame_options_header
|
46
47
|
before_filter :set_csp_header
|
47
48
|
before_filter :set_x_xss_protection_header
|
@@ -61,6 +62,7 @@ module SecureHeaders
|
|
61
62
|
def set_security_headers(options = self.class.secure_headers_options)
|
62
63
|
set_csp_header(request, options[:csp])
|
63
64
|
set_hsts_header(options[:hsts])
|
65
|
+
set_hpkp_header(options[:hpkp])
|
64
66
|
set_x_frame_options_header(options[:x_frame_options])
|
65
67
|
set_x_xss_protection_header(options[:x_xss_protection])
|
66
68
|
set_x_content_type_options_header(options[:x_content_type_options])
|
@@ -136,6 +138,16 @@ module SecureHeaders
|
|
136
138
|
set_a_header(:hsts, StrictTransportSecurity, options)
|
137
139
|
end
|
138
140
|
|
141
|
+
def set_hpkp_header(options=self.class.secure_headers_options[:hpkp])
|
142
|
+
return unless request.ssl?
|
143
|
+
config = self.class.options_for :hpkp, options
|
144
|
+
|
145
|
+
return if config == false || config.nil?
|
146
|
+
|
147
|
+
hpkp_header = PublicKeyPins.new(config)
|
148
|
+
set_header(hpkp_header)
|
149
|
+
end
|
150
|
+
|
139
151
|
def set_x_download_options_header(options=self.class.secure_headers_options[:x_download_options])
|
140
152
|
set_a_header(:x_download_options, XDownloadOptions, options)
|
141
153
|
end
|
@@ -168,6 +180,7 @@ end
|
|
168
180
|
|
169
181
|
require "secure_headers/version"
|
170
182
|
require "secure_headers/header"
|
183
|
+
require "secure_headers/headers/public_key_pins"
|
171
184
|
require "secure_headers/headers/content_security_policy"
|
172
185
|
require "secure_headers/headers/x_frame_options"
|
173
186
|
require "secure_headers/headers/strict_transport_security"
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module SecureHeaders
|
2
|
+
class PublicKeyPinsBuildError < StandardError; end
|
3
|
+
class PublicKeyPins < Header
|
4
|
+
module Constants
|
5
|
+
HPKP_HEADER_NAME = "Public-Key-Pins"
|
6
|
+
ENV_KEY = 'secure_headers.public_key_pins'
|
7
|
+
HASH_ALGORITHMS = [:sha256]
|
8
|
+
DIRECTIVES = [:max_age]
|
9
|
+
end
|
10
|
+
class << self
|
11
|
+
def symbol_to_hyphen_case sym
|
12
|
+
sym.to_s.gsub('_', '-')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
include Constants
|
16
|
+
|
17
|
+
def initialize(config=nil)
|
18
|
+
@config = validate_config(config)
|
19
|
+
|
20
|
+
@pins = @config.fetch(:pins, nil)
|
21
|
+
@report_uri = @config.fetch(:report_uri, nil)
|
22
|
+
@app_name = @config.fetch(:app_name, nil)
|
23
|
+
@enforce = !!@config.fetch(:enforce, nil)
|
24
|
+
@include_subdomains = !!@config.fetch(:include_subdomains, nil)
|
25
|
+
@tag_report_uri = !!@config.fetch(:tag_report_uri, nil)
|
26
|
+
end
|
27
|
+
|
28
|
+
def name
|
29
|
+
base = HPKP_HEADER_NAME
|
30
|
+
if !@enforce
|
31
|
+
base += "-Report-Only"
|
32
|
+
end
|
33
|
+
base
|
34
|
+
end
|
35
|
+
|
36
|
+
def value
|
37
|
+
header_value = [
|
38
|
+
generic_directives,
|
39
|
+
pin_directives,
|
40
|
+
report_uri_directive,
|
41
|
+
subdomain_directive
|
42
|
+
].compact.join('; ').strip
|
43
|
+
end
|
44
|
+
|
45
|
+
def validate_config(config)
|
46
|
+
raise PublicKeyPinsBuildError.new("config must be a hash.") unless config.is_a? Hash
|
47
|
+
|
48
|
+
if !config[:max_age]
|
49
|
+
raise PublicKeyPinsBuildError.new("max-age is a required directive.")
|
50
|
+
elsif config[:max_age].to_s !~ /\A\d+\z/
|
51
|
+
raise PublicKeyPinsBuildError.new("max-age must be a number.
|
52
|
+
#{config[:max_age]} was supplied.")
|
53
|
+
elsif config[:pins] && config[:pins].length < 2
|
54
|
+
raise PublicKeyPinsBuildError.new("A minimum of 2 pins are required.")
|
55
|
+
end
|
56
|
+
|
57
|
+
config
|
58
|
+
end
|
59
|
+
|
60
|
+
def pin_directives
|
61
|
+
return nil if @pins.nil?
|
62
|
+
@pins.collect do |pin|
|
63
|
+
pin.map do |token, hash|
|
64
|
+
"pin-#{token}=\"#{hash}\"" if HASH_ALGORITHMS.include?(token)
|
65
|
+
end
|
66
|
+
end.join('; ')
|
67
|
+
end
|
68
|
+
|
69
|
+
def generic_directives
|
70
|
+
DIRECTIVES.collect do |directive_name|
|
71
|
+
build_directive(directive_name) if @config[directive_name]
|
72
|
+
end.join('; ')
|
73
|
+
end
|
74
|
+
|
75
|
+
def build_directive(key)
|
76
|
+
"#{self.class.symbol_to_hyphen_case(key)}=#{@config[key]}"
|
77
|
+
end
|
78
|
+
|
79
|
+
def report_uri_directive
|
80
|
+
return nil if @report_uri.nil?
|
81
|
+
|
82
|
+
if @tag_report_uri
|
83
|
+
@report_uri = "#{@report_uri}?enforce=#{@enforce}"
|
84
|
+
@report_uri += "&app_name=#{@app_name}" if @app_name
|
85
|
+
end
|
86
|
+
|
87
|
+
"report-uri=\"#{@report_uri}\""
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
def subdomain_directive
|
92
|
+
@include_subdomains ? 'includeSubDomains' : nil
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module SecureHeaders
|
4
|
+
describe PublicKeyPins do
|
5
|
+
specify{ expect(PublicKeyPins.new(:max_age => 1234).name).to eq("Public-Key-Pins-Report-Only") }
|
6
|
+
specify{ expect(PublicKeyPins.new(:max_age => 1234, :enforce => true).name).to eq("Public-Key-Pins") }
|
7
|
+
|
8
|
+
specify { expect(PublicKeyPins.new({:max_age => 1234}).value).to eq("max-age=1234")}
|
9
|
+
specify { expect(PublicKeyPins.new(:max_age => 1234).value).to eq("max-age=1234")}
|
10
|
+
specify {
|
11
|
+
config = {:max_age => 1234, :pins => [{:sha256 => 'base64encodedpin1'}, {:sha256 => 'base64encodedpin2'}]}
|
12
|
+
header_value = "max-age=1234; pin-sha256=\"base64encodedpin1\"; pin-sha256=\"base64encodedpin2\""
|
13
|
+
expect(PublicKeyPins.new(config).value).to eq(header_value)
|
14
|
+
}
|
15
|
+
|
16
|
+
context "with an invalid configuration" do
|
17
|
+
it "raises an exception when max-age is not provided" do
|
18
|
+
expect {
|
19
|
+
PublicKeyPins.new(:foo => 'bar')
|
20
|
+
}.to raise_error(PublicKeyPinsBuildError)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "raises an exception with an invalid max-age" do
|
24
|
+
expect {
|
25
|
+
PublicKeyPins.new(:max_age => 'abc123')
|
26
|
+
}.to raise_error(PublicKeyPinsBuildError)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'raises an exception with less than 2 pins' do
|
30
|
+
expect {
|
31
|
+
config = {:max_age => 1234, :pins => [{:sha256 => 'base64encodedpin'}]}
|
32
|
+
PublicKeyPins.new(config)
|
33
|
+
}.to raise_error(PublicKeyPinsBuildError)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -24,6 +24,7 @@ describe SecureHeaders do
|
|
24
24
|
|
25
25
|
def reset_config
|
26
26
|
::SecureHeaders::Configuration.configure do |config|
|
27
|
+
config.hpkp = nil
|
27
28
|
config.hsts = nil
|
28
29
|
config.x_frame_options = nil
|
29
30
|
config.x_content_type_options = nil
|
@@ -36,6 +37,7 @@ describe SecureHeaders do
|
|
36
37
|
|
37
38
|
def set_security_headers(subject)
|
38
39
|
subject.set_csp_header
|
40
|
+
subject.set_hpkp_header
|
39
41
|
subject.set_hsts_header
|
40
42
|
subject.set_x_frame_options_header
|
41
43
|
subject.set_x_content_type_options_header
|
@@ -65,6 +67,7 @@ describe SecureHeaders do
|
|
65
67
|
subject.set_csp_header
|
66
68
|
subject.set_x_frame_options_header
|
67
69
|
subject.set_hsts_header
|
70
|
+
subject.set_hpkp_header
|
68
71
|
subject.set_x_xss_protection_header
|
69
72
|
subject.set_x_content_type_options_header
|
70
73
|
subject.set_x_download_options_header
|
@@ -109,6 +112,17 @@ describe SecureHeaders do
|
|
109
112
|
subject.set_hsts_header({:include_subdomains => true})
|
110
113
|
end
|
111
114
|
|
115
|
+
it "does not set the HPKP header if disabled" do
|
116
|
+
should_not_assign_header(HPKP_HEADER_NAME)
|
117
|
+
subject.set_hpkp_header
|
118
|
+
end
|
119
|
+
|
120
|
+
it "does not set the HPKP header if request is over HTTP" do
|
121
|
+
allow(subject).to receive_message_chain(:request, :ssl?).and_return(false)
|
122
|
+
should_not_assign_header(HPKP_HEADER_NAME)
|
123
|
+
subject.set_hpkp_header(:max_age => 1234)
|
124
|
+
end
|
125
|
+
|
112
126
|
it "does not set the CSP header if disabled" do
|
113
127
|
stub_user_agent(USER_AGENTS[:chrome])
|
114
128
|
should_not_assign_header(HEADER_NAME)
|
@@ -130,6 +144,7 @@ describe SecureHeaders do
|
|
130
144
|
it "does not set any headers when disabled" do
|
131
145
|
::SecureHeaders::Configuration.configure do |config|
|
132
146
|
config.hsts = false
|
147
|
+
config.hpkp = false
|
133
148
|
config.x_frame_options = false
|
134
149
|
config.x_content_type_options = false
|
135
150
|
config.x_xss_protection = false
|
@@ -190,6 +205,38 @@ describe SecureHeaders do
|
|
190
205
|
end
|
191
206
|
end
|
192
207
|
|
208
|
+
describe "#set_public_key_pins" do
|
209
|
+
it "sets the Public-Key-Pins header" do
|
210
|
+
should_assign_header(HPKP_HEADER_NAME + "-Report-Only", "max-age=1234")
|
211
|
+
subject.set_hpkp_header(:max_age => 1234)
|
212
|
+
end
|
213
|
+
|
214
|
+
it "allows you to enforce public key pinning" do
|
215
|
+
should_assign_header(HPKP_HEADER_NAME, "max-age=1234")
|
216
|
+
subject.set_hpkp_header(:max_age => 1234, :enforce => true)
|
217
|
+
end
|
218
|
+
|
219
|
+
it "allows you to specific a custom max-age value" do
|
220
|
+
should_assign_header(HPKP_HEADER_NAME + "-Report-Only", 'max-age=1234')
|
221
|
+
subject.set_hpkp_header(:max_age => 1234)
|
222
|
+
end
|
223
|
+
|
224
|
+
it "allows you to specify includeSubdomains" do
|
225
|
+
should_assign_header(HPKP_HEADER_NAME, "max-age=1234; includeSubDomains")
|
226
|
+
subject.set_hpkp_header(:max_age => 1234, :include_subdomains => true, :enforce => true)
|
227
|
+
end
|
228
|
+
|
229
|
+
it "allows you to specify a report-uri" do
|
230
|
+
should_assign_header(HPKP_HEADER_NAME, "max-age=1234; report-uri=\"https://foobar.com\"")
|
231
|
+
subject.set_hpkp_header(:max_age => 1234, :report_uri => "https://foobar.com", :enforce => true)
|
232
|
+
end
|
233
|
+
|
234
|
+
it "allows you to specify a report-uri with app_name" do
|
235
|
+
should_assign_header(HPKP_HEADER_NAME, "max-age=1234; report-uri=\"https://foobar.com?enforce=true&app_name=my_app\"")
|
236
|
+
subject.set_hpkp_header(:max_age => 1234, :report_uri => "https://foobar.com", :app_name => "my_app", :tag_report_uri => true, :enforce => true)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
193
240
|
describe "#set_x_xss_protection" do
|
194
241
|
it "sets the X-XSS-Protection header" do
|
195
242
|
should_assign_header(X_XSS_PROTECTION_HEADER_NAME, SecureHeaders::XXssProtection::Constants::DEFAULT_VALUE)
|
data/spec/spec_helper.rb
CHANGED
@@ -7,6 +7,7 @@ if defined?(Coveralls)
|
|
7
7
|
Coveralls.wear!
|
8
8
|
end
|
9
9
|
|
10
|
+
include ::SecureHeaders::PublicKeyPins::Constants
|
10
11
|
include ::SecureHeaders::StrictTransportSecurity::Constants
|
11
12
|
include ::SecureHeaders::ContentSecurityPolicy::Constants
|
12
13
|
include ::SecureHeaders::XFrameOptions::Constants
|
metadata
CHANGED
@@ -1,30 +1,27 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: secure_headers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0
|
5
|
-
prerelease:
|
4
|
+
version: 2.1.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Neil Matatall
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2015-05-
|
11
|
+
date: 2015-05-07 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: rake
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - ">="
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: '0'
|
22
20
|
type: :development
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - ">="
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: '0'
|
30
27
|
description: Security related headers all in one gem.
|
@@ -34,10 +31,10 @@ executables: []
|
|
34
31
|
extensions: []
|
35
32
|
extra_rdoc_files: []
|
36
33
|
files:
|
37
|
-
- .gitignore
|
38
|
-
- .ruby-gemset
|
39
|
-
- .ruby-version
|
40
|
-
- .travis.yml
|
34
|
+
- ".gitignore"
|
35
|
+
- ".ruby-gemset"
|
36
|
+
- ".ruby-version"
|
37
|
+
- ".travis.yml"
|
41
38
|
- Gemfile
|
42
39
|
- LICENSE
|
43
40
|
- README.md
|
@@ -130,6 +127,7 @@ files:
|
|
130
127
|
- lib/secure_headers/header.rb
|
131
128
|
- lib/secure_headers/headers/content_security_policy.rb
|
132
129
|
- lib/secure_headers/headers/content_security_policy/script_hash_middleware.rb
|
130
|
+
- lib/secure_headers/headers/public_key_pins.rb
|
133
131
|
- lib/secure_headers/headers/strict_transport_security.rb
|
134
132
|
- lib/secure_headers/headers/x_content_type_options.rb
|
135
133
|
- lib/secure_headers/headers/x_download_options.rb
|
@@ -144,6 +142,7 @@ files:
|
|
144
142
|
- secure_headers.gemspec
|
145
143
|
- spec/lib/secure_headers/headers/content_security_policy/script_hash_middleware_spec.rb
|
146
144
|
- spec/lib/secure_headers/headers/content_security_policy_spec.rb
|
145
|
+
- spec/lib/secure_headers/headers/public_key_pins_spec.rb
|
147
146
|
- spec/lib/secure_headers/headers/strict_transport_security_spec.rb
|
148
147
|
- spec/lib/secure_headers/headers/x_content_type_options_spec.rb
|
149
148
|
- spec/lib/secure_headers/headers/x_download_options_spec.rb
|
@@ -156,32 +155,32 @@ files:
|
|
156
155
|
homepage: https://github.com/twitter/secureheaders
|
157
156
|
licenses:
|
158
157
|
- Apache Public License 2.0
|
158
|
+
metadata: {}
|
159
159
|
post_install_message:
|
160
160
|
rdoc_options: []
|
161
161
|
require_paths:
|
162
162
|
- lib
|
163
163
|
required_ruby_version: !ruby/object:Gem::Requirement
|
164
|
-
none: false
|
165
164
|
requirements:
|
166
|
-
- -
|
165
|
+
- - ">="
|
167
166
|
- !ruby/object:Gem::Version
|
168
167
|
version: '0'
|
169
168
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
170
|
-
none: false
|
171
169
|
requirements:
|
172
|
-
- -
|
170
|
+
- - ">="
|
173
171
|
- !ruby/object:Gem::Version
|
174
172
|
version: '0'
|
175
173
|
requirements: []
|
176
174
|
rubyforge_project:
|
177
|
-
rubygems_version:
|
175
|
+
rubygems_version: 2.2.3
|
178
176
|
signing_key:
|
179
|
-
specification_version:
|
177
|
+
specification_version: 4
|
180
178
|
summary: Add easily configured security headers to responses including content-security-policy,
|
181
179
|
x-frame-options, strict-transport-security, etc.
|
182
180
|
test_files:
|
183
181
|
- spec/lib/secure_headers/headers/content_security_policy/script_hash_middleware_spec.rb
|
184
182
|
- spec/lib/secure_headers/headers/content_security_policy_spec.rb
|
183
|
+
- spec/lib/secure_headers/headers/public_key_pins_spec.rb
|
185
184
|
- spec/lib/secure_headers/headers/strict_transport_security_spec.rb
|
186
185
|
- spec/lib/secure_headers/headers/x_content_type_options_spec.rb
|
187
186
|
- spec/lib/secure_headers/headers/x_download_options_spec.rb
|