secure_headers 3.9.0 → 4.0.0.alpha01
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 +5 -5
- data/.rspec +1 -0
- data/.rubocop.yml +3 -0
- data/.ruby-version +1 -1
- data/.travis.yml +8 -6
- data/CHANGELOG.md +2 -34
- data/CONTRIBUTING.md +1 -1
- data/Gemfile +7 -4
- data/Guardfile +1 -0
- data/README.md +4 -25
- data/Rakefile +22 -18
- data/docs/cookies.md +18 -5
- data/lib/secure_headers.rb +1 -2
- data/lib/secure_headers/configuration.rb +6 -16
- data/lib/secure_headers/hash_helper.rb +2 -1
- data/lib/secure_headers/headers/clear_site_data.rb +2 -1
- data/lib/secure_headers/headers/content_security_policy.rb +14 -60
- data/lib/secure_headers/headers/content_security_policy_config.rb +1 -1
- data/lib/secure_headers/headers/cookie.rb +22 -10
- data/lib/secure_headers/headers/policy_management.rb +57 -98
- data/lib/secure_headers/headers/public_key_pins.rb +4 -3
- data/lib/secure_headers/headers/referrer_policy.rb +1 -0
- data/lib/secure_headers/headers/strict_transport_security.rb +2 -1
- data/lib/secure_headers/headers/x_content_type_options.rb +1 -0
- data/lib/secure_headers/headers/x_download_options.rb +2 -1
- data/lib/secure_headers/headers/x_frame_options.rb +1 -0
- data/lib/secure_headers/headers/x_permitted_cross_domain_policies.rb +2 -1
- data/lib/secure_headers/headers/x_xss_protection.rb +2 -1
- data/lib/secure_headers/middleware.rb +10 -9
- data/lib/secure_headers/railtie.rb +7 -6
- data/lib/secure_headers/utils/cookies_config.rb +17 -18
- data/lib/secure_headers/view_helper.rb +2 -1
- data/lib/tasks/tasks.rake +2 -1
- data/secure_headers.gemspec +13 -3
- data/spec/lib/secure_headers/configuration_spec.rb +9 -8
- data/spec/lib/secure_headers/headers/clear_site_data_spec.rb +2 -1
- data/spec/lib/secure_headers/headers/content_security_policy_spec.rb +17 -53
- data/spec/lib/secure_headers/headers/cookie_spec.rb +58 -37
- data/spec/lib/secure_headers/headers/policy_management_spec.rb +20 -41
- data/spec/lib/secure_headers/headers/public_key_pins_spec.rb +7 -6
- data/spec/lib/secure_headers/headers/referrer_policy_spec.rb +4 -3
- data/spec/lib/secure_headers/headers/strict_transport_security_spec.rb +5 -4
- data/spec/lib/secure_headers/headers/x_content_type_options_spec.rb +2 -1
- data/spec/lib/secure_headers/headers/x_download_options_spec.rb +3 -2
- data/spec/lib/secure_headers/headers/x_frame_options_spec.rb +2 -1
- data/spec/lib/secure_headers/headers/x_permitted_cross_domain_policies_spec.rb +4 -3
- data/spec/lib/secure_headers/headers/x_xss_protection_spec.rb +4 -3
- data/spec/lib/secure_headers/middleware_spec.rb +18 -21
- data/spec/lib/secure_headers/view_helpers_spec.rb +5 -4
- data/spec/lib/secure_headers_spec.rb +92 -120
- data/spec/spec_helper.rb +9 -23
- data/upgrading-to-4-0.md +49 -0
- metadata +16 -11
- data/lib/secure_headers/headers/expect_certificate_transparency.rb +0 -70
- data/spec/lib/secure_headers/headers/expect_certificate_transparency_spec.rb +0 -42
data/spec/spec_helper.rb
CHANGED
@@ -1,12 +1,11 @@
|
|
1
|
-
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
|
6
|
-
require 'coveralls'
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "rubygems"
|
3
|
+
require "rspec"
|
4
|
+
require "rack"
|
5
|
+
require "coveralls"
|
7
6
|
Coveralls.wear!
|
8
7
|
|
9
|
-
require File.join(File.dirname(__FILE__),
|
8
|
+
require File.join(File.dirname(__FILE__), "..", "lib", "secure_headers")
|
10
9
|
|
11
10
|
|
12
11
|
|
@@ -14,9 +13,9 @@ USER_AGENTS = {
|
|
14
13
|
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",
|
15
14
|
firefox: "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:14.0) Gecko/20100101 Firefox/14.0.1",
|
16
15
|
firefox46: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:46.0) Gecko/20100101 Firefox/46.0",
|
17
|
-
chrome:
|
18
|
-
ie:
|
19
|
-
opera:
|
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",
|
17
|
+
ie: "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/5.0)",
|
18
|
+
opera: "Opera/9.80 (Windows NT 6.1; U; es-ES) Presto/2.9.181 Version/12.00",
|
20
19
|
ios5: "Mozilla/5.0 (iPhone; CPU iPhone OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3",
|
21
20
|
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
21
|
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",
|
@@ -34,7 +33,6 @@ def expect_default_values(hash)
|
|
34
33
|
expect(hash[SecureHeaders::XContentTypeOptions::HEADER_NAME]).to eq(SecureHeaders::XContentTypeOptions::DEFAULT_VALUE)
|
35
34
|
expect(hash[SecureHeaders::XPermittedCrossDomainPolicies::HEADER_NAME]).to eq(SecureHeaders::XPermittedCrossDomainPolicies::DEFAULT_VALUE)
|
36
35
|
expect(hash[SecureHeaders::ReferrerPolicy::HEADER_NAME]).to be_nil
|
37
|
-
expect(hash[SecureHeaders::ExpectCertificateTransparency::HEADER_NAME]).to be_nil
|
38
36
|
end
|
39
37
|
|
40
38
|
module SecureHeaders
|
@@ -50,15 +48,3 @@ end
|
|
50
48
|
def reset_config
|
51
49
|
SecureHeaders::Configuration.clear_configurations
|
52
50
|
end
|
53
|
-
|
54
|
-
def capture_warning
|
55
|
-
begin
|
56
|
-
old_stderr = $stderr
|
57
|
-
$stderr = StringIO.new
|
58
|
-
yield
|
59
|
-
result = $stderr.string
|
60
|
-
ensure
|
61
|
-
$stderr = old_stderr
|
62
|
-
end
|
63
|
-
result
|
64
|
-
end
|
data/upgrading-to-4-0.md
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
### Breaking Changes
|
2
|
+
|
3
|
+
The most likely change to break your app is the new cookie defaults. This is the first place to check. If you're using the default CSP, your policy will change but your app should not break. This should not break brand new projects using secure_headers either.
|
4
|
+
|
5
|
+
## All cookies default to secure/httponly/SameSite=Lax
|
6
|
+
|
7
|
+
By default, *all* cookies will be marked as `SameSite=lax`,`secure`, and `httponly`. To opt-out, supply `OPT_OUT` as the value for `SecureHeaders.cookies` or the individual configs. Setting these values to `false` will raise an error.
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
# specific opt outs
|
11
|
+
config.cookies = {
|
12
|
+
secure: OPT_OUT,
|
13
|
+
httponly: OPT_OUT,
|
14
|
+
samesite: OPT_OUT,
|
15
|
+
}
|
16
|
+
|
17
|
+
# nuclear option, just make things work again
|
18
|
+
config.cookies = OPT_OUT
|
19
|
+
```
|
20
|
+
|
21
|
+
## Default Content Security Policy
|
22
|
+
|
23
|
+
The default CSP has changed to be more universal without sacrificing too much security.
|
24
|
+
|
25
|
+
* Flash/Java disabled by default
|
26
|
+
* `img-src` allows data: images and favicons (among others)
|
27
|
+
* `style-src` allows inline CSS by default (most find it impossible/impractical to remove inline content today)
|
28
|
+
* `form-action` (not governed by `default-src`, practically treated as `*`) is set to `'self'`
|
29
|
+
|
30
|
+
Previously, the default CSP was:
|
31
|
+
|
32
|
+
`Content-Security-Policy: default-src 'self'`
|
33
|
+
|
34
|
+
The new default policy is:
|
35
|
+
|
36
|
+
`default-src https:; form-action 'self'; img-src https: data: 'self'; object-src 'none'; script-src https:; style-src 'self' 'unsafe-inline' https:`
|
37
|
+
|
38
|
+
## CSP configuration
|
39
|
+
|
40
|
+
* Setting `report_only: true` in a CSP config will raise an error. Instead, set `csp_report_only`.
|
41
|
+
* Setting `frame_src` and `child_src` when values don't match will raise an error. Just use `frame_src`.
|
42
|
+
|
43
|
+
## config.secure_cookies removed
|
44
|
+
|
45
|
+
Use `config.cookies` instead.
|
46
|
+
|
47
|
+
## Supported ruby versions
|
48
|
+
|
49
|
+
We've dropped support for ruby versions <= 2.2. Sorry.
|
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:
|
4
|
+
version: 4.0.0.alpha01
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Neil Matatall
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-07-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 0.15.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 0.15.0
|
41
41
|
description: Manages application of security headers with many safe defaults.
|
42
42
|
email:
|
43
43
|
- neil.matatall@gmail.com
|
@@ -49,6 +49,7 @@ files:
|
|
49
49
|
- ".github/PULL_REQUEST_TEMPLATE.md"
|
50
50
|
- ".gitignore"
|
51
51
|
- ".rspec"
|
52
|
+
- ".rubocop.yml"
|
52
53
|
- ".ruby-gemset"
|
53
54
|
- ".ruby-version"
|
54
55
|
- ".travis.yml"
|
@@ -73,7 +74,6 @@ files:
|
|
73
74
|
- lib/secure_headers/headers/content_security_policy.rb
|
74
75
|
- lib/secure_headers/headers/content_security_policy_config.rb
|
75
76
|
- lib/secure_headers/headers/cookie.rb
|
76
|
-
- lib/secure_headers/headers/expect_certificate_transparency.rb
|
77
77
|
- lib/secure_headers/headers/policy_management.rb
|
78
78
|
- lib/secure_headers/headers/public_key_pins.rb
|
79
79
|
- lib/secure_headers/headers/referrer_policy.rb
|
@@ -93,7 +93,6 @@ files:
|
|
93
93
|
- spec/lib/secure_headers/headers/clear_site_data_spec.rb
|
94
94
|
- spec/lib/secure_headers/headers/content_security_policy_spec.rb
|
95
95
|
- spec/lib/secure_headers/headers/cookie_spec.rb
|
96
|
-
- spec/lib/secure_headers/headers/expect_certificate_transparency_spec.rb
|
97
96
|
- spec/lib/secure_headers/headers/policy_management_spec.rb
|
98
97
|
- spec/lib/secure_headers/headers/public_key_pins_spec.rb
|
99
98
|
- spec/lib/secure_headers/headers/referrer_policy_spec.rb
|
@@ -108,11 +107,17 @@ files:
|
|
108
107
|
- spec/lib/secure_headers_spec.rb
|
109
108
|
- spec/spec_helper.rb
|
110
109
|
- upgrading-to-3-0.md
|
110
|
+
- upgrading-to-4-0.md
|
111
111
|
homepage: https://github.com/twitter/secureheaders
|
112
112
|
licenses:
|
113
113
|
- Apache Public License 2.0
|
114
114
|
metadata: {}
|
115
|
-
post_install_message:
|
115
|
+
post_install_message: |2+
|
116
|
+
|
117
|
+
**********
|
118
|
+
:wave: secure_headers 4.0 introduces a lot of breaking changes (in the name of security!). It's highly likely you will need to update your secure_headers cookie configuration to avoid breaking things. See the upgrade guide for details: https://github.com/twitter/secureheaders/blob/master/upgrading-to-4-0.md
|
119
|
+
**********
|
120
|
+
|
116
121
|
rdoc_options: []
|
117
122
|
require_paths:
|
118
123
|
- lib
|
@@ -123,11 +128,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
123
128
|
version: '0'
|
124
129
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
125
130
|
requirements:
|
126
|
-
- - "
|
131
|
+
- - ">"
|
127
132
|
- !ruby/object:Gem::Version
|
128
|
-
version:
|
133
|
+
version: 1.3.1
|
129
134
|
requirements: []
|
130
|
-
|
135
|
+
rubyforge_project:
|
136
|
+
rubygems_version: 2.6.11
|
131
137
|
signing_key:
|
132
138
|
specification_version: 4
|
133
139
|
summary: Add easily configured security headers to responses including content-security-policy,
|
@@ -137,7 +143,6 @@ test_files:
|
|
137
143
|
- spec/lib/secure_headers/headers/clear_site_data_spec.rb
|
138
144
|
- spec/lib/secure_headers/headers/content_security_policy_spec.rb
|
139
145
|
- spec/lib/secure_headers/headers/cookie_spec.rb
|
140
|
-
- spec/lib/secure_headers/headers/expect_certificate_transparency_spec.rb
|
141
146
|
- spec/lib/secure_headers/headers/policy_management_spec.rb
|
142
147
|
- spec/lib/secure_headers/headers/public_key_pins_spec.rb
|
143
148
|
- spec/lib/secure_headers/headers/referrer_policy_spec.rb
|
@@ -1,70 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
module SecureHeaders
|
3
|
-
class ExpectCertificateTransparencyConfigError < StandardError; end
|
4
|
-
|
5
|
-
class ExpectCertificateTransparency
|
6
|
-
HEADER_NAME = "Expect-CT".freeze
|
7
|
-
CONFIG_KEY = :expect_certificate_transparency
|
8
|
-
INVALID_CONFIGURATION_ERROR = "config must be a hash.".freeze
|
9
|
-
INVALID_ENFORCE_VALUE_ERROR = "enforce must be a boolean".freeze
|
10
|
-
REQUIRED_MAX_AGE_ERROR = "max-age is a required directive.".freeze
|
11
|
-
INVALID_MAX_AGE_ERROR = "max-age must be a number.".freeze
|
12
|
-
|
13
|
-
class << self
|
14
|
-
# Public: Generate a Expect-CT header.
|
15
|
-
#
|
16
|
-
# Returns nil if not configured, returns header name and value if
|
17
|
-
# configured.
|
18
|
-
def make_header(config)
|
19
|
-
return if config.nil?
|
20
|
-
|
21
|
-
header = new(config)
|
22
|
-
[HEADER_NAME, header.value]
|
23
|
-
end
|
24
|
-
|
25
|
-
def validate_config!(config)
|
26
|
-
return if config.nil? || config == OPT_OUT
|
27
|
-
raise ExpectCertificateTransparencyConfigError.new(INVALID_CONFIGURATION_ERROR) unless config.is_a? Hash
|
28
|
-
|
29
|
-
unless [true, false, nil].include?(config[:enforce])
|
30
|
-
raise ExpectCertificateTransparencyConfigError.new(INVALID_ENFORCE_VALUE_ERROR)
|
31
|
-
end
|
32
|
-
|
33
|
-
if !config[:max_age]
|
34
|
-
raise ExpectCertificateTransparencyConfigError.new(REQUIRED_MAX_AGE_ERROR)
|
35
|
-
elsif config[:max_age].to_s !~ /\A\d+\z/
|
36
|
-
raise ExpectCertificateTransparencyConfigError.new(INVALID_MAX_AGE_ERROR)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def initialize(config)
|
42
|
-
@enforced = config.fetch(:enforce, nil)
|
43
|
-
@max_age = config.fetch(:max_age, nil)
|
44
|
-
@report_uri = config.fetch(:report_uri, nil)
|
45
|
-
end
|
46
|
-
|
47
|
-
def value
|
48
|
-
header_value = [
|
49
|
-
enforced_directive,
|
50
|
-
max_age_directive,
|
51
|
-
report_uri_directive
|
52
|
-
].compact.join(", ").strip
|
53
|
-
end
|
54
|
-
|
55
|
-
def enforced_directive
|
56
|
-
# Unfortunately `if @enforced` isn't enough here in case someone
|
57
|
-
# passes in a random string so let's be specific with it to prevent
|
58
|
-
# accidental enforcement.
|
59
|
-
"enforce" if @enforced == true
|
60
|
-
end
|
61
|
-
|
62
|
-
def max_age_directive
|
63
|
-
"max-age=#{@max_age}" if @max_age
|
64
|
-
end
|
65
|
-
|
66
|
-
def report_uri_directive
|
67
|
-
"report-uri=\"#{@report_uri}\"" if @report_uri
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
@@ -1,42 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require "spec_helper"
|
3
|
-
|
4
|
-
module SecureHeaders
|
5
|
-
describe ExpectCertificateTransparency do
|
6
|
-
specify { expect(ExpectCertificateTransparency.new(max_age: 1234, enforce: true).value).to eq("enforce, max-age=1234") }
|
7
|
-
specify { expect(ExpectCertificateTransparency.new(max_age: 1234, enforce: false).value).to eq("max-age=1234") }
|
8
|
-
specify { expect(ExpectCertificateTransparency.new(max_age: 1234, enforce: "yolocopter").value).to eq("max-age=1234") }
|
9
|
-
specify { expect(ExpectCertificateTransparency.new(max_age: 1234, report_uri: "https://report-uri.io/expect-ct").value).to eq("max-age=1234, report-uri=\"https://report-uri.io/expect-ct\"") }
|
10
|
-
specify do
|
11
|
-
config = { enforce: true, max_age: 1234, report_uri: "https://report-uri.io/expect-ct" }
|
12
|
-
header_value = "enforce, max-age=1234, report-uri=\"https://report-uri.io/expect-ct\""
|
13
|
-
expect(ExpectCertificateTransparency.new(config).value).to eq(header_value)
|
14
|
-
end
|
15
|
-
|
16
|
-
context "with an invalid configuration" do
|
17
|
-
it "raises an exception when configuration isn't a hash" do
|
18
|
-
expect do
|
19
|
-
ExpectCertificateTransparency.validate_config!(%w(a))
|
20
|
-
end.to raise_error(ExpectCertificateTransparencyConfigError)
|
21
|
-
end
|
22
|
-
|
23
|
-
it "raises an exception when max-age is not provided" do
|
24
|
-
expect do
|
25
|
-
ExpectCertificateTransparency.validate_config!(foo: "bar")
|
26
|
-
end.to raise_error(ExpectCertificateTransparencyConfigError)
|
27
|
-
end
|
28
|
-
|
29
|
-
it "raises an exception with an invalid max-age" do
|
30
|
-
expect do
|
31
|
-
ExpectCertificateTransparency.validate_config!(max_age: "abc123")
|
32
|
-
end.to raise_error(ExpectCertificateTransparencyConfigError)
|
33
|
-
end
|
34
|
-
|
35
|
-
it "raises an exception with an invalid enforce value" do
|
36
|
-
expect do
|
37
|
-
ExpectCertificateTransparency.validate_config!(enforce: "brokenstring")
|
38
|
-
end.to raise_error(ExpectCertificateTransparencyConfigError)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|