secure_headers 6.0.0.alpha02 → 6.0.0.alpha03
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 +4 -4
- data/docs/upgrading-to-6-0.md +3 -7
- data/lib/secure_headers.rb +1 -3
- data/lib/secure_headers/configuration.rb +2 -2
- data/lib/secure_headers/headers/content_security_policy.rb +5 -58
- data/lib/secure_headers/headers/policy_management.rb +3 -55
- data/secure_headers.gemspec +1 -2
- data/spec/lib/secure_headers/headers/content_security_policy_spec.rb +1 -64
- data/spec/lib/secure_headers/headers/policy_management_spec.rb +2 -2
- data/spec/lib/secure_headers_spec.rb +0 -37
- metadata +2 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 259a48a1ed38b03c3ccae4f8207fefab853402af
|
4
|
+
data.tar.gz: '03080810eb7b3d841761e70de6f8486aabe8e513'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5385731dcde51434ad2f217f7bc92ca699c3cfa554520d21d304f72d9508ec40122dd17795aaf3813e0aa190dafd7bba8ce23cfc87480858ed351d4712da72ea
|
7
|
+
data.tar.gz: 9ff3abe4499abebfa633568dca63ea7f6cabaf0fc2a98c88426c065d149504ee6e8b3363f800243895088c1ae9ede8eed6a8e00d15255fff2186e80eff7c496e
|
data/docs/upgrading-to-6-0.md
CHANGED
@@ -35,10 +35,6 @@ These classes are typically not directly instantiated by users of SecureHeaders.
|
|
35
35
|
|
36
36
|
This method is not typically directly called by users of SecureHeaders. Given that named overrides are no longer statically stored, fetching them no longer makes sense.
|
37
37
|
|
38
|
-
## `content_security_policy_nonce` has been renamed
|
39
|
-
|
40
|
-
While tag helpers such as `nonced_javascript_tag` and `nonced_style_tag`, the value for the nonce was available via `content_security_policy_nonce`. Rails 5.2 has implemented a method with the same name but clashes with the number of arguments. It has been renamed to`_content_security_policy_nonce` and will likely be removed in future versions.
|
41
|
-
|
42
38
|
## Configuration headers are no longer cached
|
43
39
|
|
44
40
|
Prior to 6.0.0 SecureHeaders pre-built and cached the headers that corresponded to the default configuration. The same was also done for named overrides. However, now that named overrides are applied dynamically, those can no longer be cached. As a result, caching has been removed in the name of simplicity. Some micro-benchmarks indicate this shouldn't be a performance problem and will help to eliminate a class of bugs entirely.
|
@@ -47,8 +43,8 @@ Prior to 6.0.0 SecureHeaders pre-built and cached the headers that corresponded
|
|
47
43
|
|
48
44
|
Prior to 6.0.0 you could conceivably, though unlikely, have `Configure#default` called more than once. Because configurations are dynamic, configuring more than once could result in unexpected behavior. So, as of 6.0.0 we raise `AlreadyConfiguredError` if the default configuration is setup more than once.
|
49
45
|
|
50
|
-
##
|
46
|
+
## All user agent sniffing has been removed
|
51
47
|
|
52
|
-
|
48
|
+
The policy configured is the policy that is delivered in terms of which directives are sent. We still dedup, strip schemes, and look for other optimizations but we will not e.g. conditionally send `frame-src` / `child-src` or apply `nonce`s / `unsafe-inline`.
|
53
49
|
|
54
|
-
The
|
50
|
+
The primary reason for these per-browser customization was to reduce console warnings. This has lead to many bugs and results inc confusing behavior. Also, console logs are incredibly noisy today and increasingly warn you about perfectly valid things (like sending `X-Frame-Options` and `frame-ancestors` together).
|
data/lib/secure_headers.rb
CHANGED
@@ -15,7 +15,6 @@ require "secure_headers/headers/expect_certificate_transparency"
|
|
15
15
|
require "secure_headers/middleware"
|
16
16
|
require "secure_headers/railtie"
|
17
17
|
require "secure_headers/view_helper"
|
18
|
-
require "useragent"
|
19
18
|
require "singleton"
|
20
19
|
require "secure_headers/configuration"
|
21
20
|
|
@@ -149,8 +148,7 @@ module SecureHeaders
|
|
149
148
|
prevent_dup = true
|
150
149
|
config = config_for(request, prevent_dup)
|
151
150
|
config.validate_config!
|
152
|
-
|
153
|
-
headers = config.generate_headers(user_agent)
|
151
|
+
headers = config.generate_headers
|
154
152
|
|
155
153
|
if request.scheme != HTTPS
|
156
154
|
HTTPS_HEADER_CLASSES.each do |klass|
|
@@ -194,11 +194,11 @@ module SecureHeaders
|
|
194
194
|
self
|
195
195
|
end
|
196
196
|
|
197
|
-
def generate_headers
|
197
|
+
def generate_headers
|
198
198
|
headers = {}
|
199
199
|
HEADERABLE_ATTRIBUTES.each do |attr|
|
200
200
|
klass = CONFIG_ATTRIBUTES_TO_HEADER_CLASSES[attr]
|
201
|
-
header_name, value = klass.make_header(instance_variable_get("@#{attr}")
|
201
|
+
header_name, value = klass.make_header(instance_variable_get("@#{attr}"))
|
202
202
|
if header_name && value
|
203
203
|
headers[header_name] = value
|
204
204
|
end
|
@@ -1,19 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require_relative "policy_management"
|
3
3
|
require_relative "content_security_policy_config"
|
4
|
-
require "useragent"
|
5
4
|
|
6
5
|
module SecureHeaders
|
7
6
|
class ContentSecurityPolicy
|
8
7
|
include PolicyManagement
|
9
8
|
|
10
|
-
|
11
|
-
VERSION_46 = ::UserAgent::Version.new("46")
|
12
|
-
VERSION_10 = ::UserAgent::Version.new("10")
|
13
|
-
FALLBACK_VERSION = ::UserAgent::Version.new("0")
|
14
|
-
|
15
|
-
def initialize(config = nil, user_agent = OTHER)
|
16
|
-
user_agent ||= OTHER
|
9
|
+
def initialize(config = nil)
|
17
10
|
@config = if config.is_a?(Hash)
|
18
11
|
if config[:report_only]
|
19
12
|
ContentSecurityPolicyReportOnlyConfig.new(config || DEFAULT_CONFIG)
|
@@ -26,12 +19,6 @@ module SecureHeaders
|
|
26
19
|
config
|
27
20
|
end
|
28
21
|
|
29
|
-
@parsed_ua = if user_agent.is_a?(UserAgent::Browsers::Base)
|
30
|
-
user_agent
|
31
|
-
else
|
32
|
-
UserAgent.parse(user_agent)
|
33
|
-
end
|
34
|
-
@frame_src = normalize_child_frame_src
|
35
22
|
@preserve_schemes = @config.preserve_schemes
|
36
23
|
@script_nonce = @config.script_nonce
|
37
24
|
@style_nonce = @config.style_nonce
|
@@ -56,20 +43,10 @@ module SecureHeaders
|
|
56
43
|
|
57
44
|
private
|
58
45
|
|
59
|
-
def normalize_child_frame_src
|
60
|
-
if @config.frame_src && @config.child_src && @config.frame_src != @config.child_src
|
61
|
-
raise ArgumentError, "#{Kernel.caller.first}: both :child_src and :frame_src supplied and do not match. This can lead to inconsistent behavior across browsers."
|
62
|
-
end
|
63
|
-
|
64
|
-
@config.frame_src || @config.child_src
|
65
|
-
end
|
66
|
-
|
67
46
|
# Private: converts the config object into a string representing a policy.
|
68
47
|
# Places default-src at the first directive and report-uri as the last. All
|
69
48
|
# others are presented in alphabetical order.
|
70
49
|
#
|
71
|
-
# Unsupported directives are filtered based on the user agent.
|
72
|
-
#
|
73
50
|
# Returns a content security policy header value.
|
74
51
|
def build_value
|
75
52
|
directives.map do |directive_name|
|
@@ -125,18 +102,7 @@ module SecureHeaders
|
|
125
102
|
#
|
126
103
|
# Returns a string representing a directive.
|
127
104
|
def build_source_list_directive(directive)
|
128
|
-
source_list =
|
129
|
-
when :child_src
|
130
|
-
if supported_directives.include?(:child_src)
|
131
|
-
@frame_src
|
132
|
-
end
|
133
|
-
when :frame_src
|
134
|
-
unless supported_directives.include?(:child_src)
|
135
|
-
@frame_src
|
136
|
-
end
|
137
|
-
else
|
138
|
-
@config.directive_value(directive)
|
139
|
-
end
|
105
|
+
source_list = @config.directive_value(directive)
|
140
106
|
|
141
107
|
if source_list != OPT_OUT && source_list && source_list.any?
|
142
108
|
normalized_source_list = minify_source_list(directive, source_list)
|
@@ -219,13 +185,13 @@ module SecureHeaders
|
|
219
185
|
source_list
|
220
186
|
end
|
221
187
|
|
222
|
-
# Private: return the list of directives
|
188
|
+
# Private: return the list of directives,
|
223
189
|
# starting with default-src and ending with report-uri.
|
224
190
|
def directives
|
225
191
|
[
|
226
192
|
DEFAULT_SRC,
|
227
|
-
BODY_DIRECTIVES
|
228
|
-
REPORT_URI
|
193
|
+
BODY_DIRECTIVES,
|
194
|
+
REPORT_URI,
|
229
195
|
].flatten
|
230
196
|
end
|
231
197
|
|
@@ -234,25 +200,6 @@ module SecureHeaders
|
|
234
200
|
source_list.map { |source_expression| source_expression.sub(HTTP_SCHEME_REGEX, "") }
|
235
201
|
end
|
236
202
|
|
237
|
-
# Private: determine which directives are supported for the given user agent.
|
238
|
-
#
|
239
|
-
# Add UA-sniffing special casing here.
|
240
|
-
#
|
241
|
-
# Returns an array of symbols representing the directives.
|
242
|
-
def supported_directives
|
243
|
-
@supported_directives ||= if VARIATIONS[@parsed_ua.browser]
|
244
|
-
if @parsed_ua.browser == "Firefox" && ((@parsed_ua.version || FALLBACK_VERSION) >= VERSION_46)
|
245
|
-
VARIATIONS["FirefoxTransitional"]
|
246
|
-
elsif @parsed_ua.browser == "Safari" && ((@parsed_ua.version || FALLBACK_VERSION) >= VERSION_10)
|
247
|
-
VARIATIONS["SafariTransitional"]
|
248
|
-
else
|
249
|
-
VARIATIONS[@parsed_ua.browser]
|
250
|
-
end
|
251
|
-
else
|
252
|
-
VARIATIONS[OTHER]
|
253
|
-
end
|
254
|
-
end
|
255
|
-
|
256
203
|
def symbol_to_hyphen_case(sym)
|
257
204
|
sym.to_s.tr("_", "-")
|
258
205
|
end
|
@@ -81,58 +81,12 @@ module SecureHeaders
|
|
81
81
|
UPGRADE_INSECURE_REQUESTS
|
82
82
|
].flatten.freeze
|
83
83
|
|
84
|
-
EDGE_DIRECTIVES = DIRECTIVES_1_0
|
85
|
-
SAFARI_DIRECTIVES = DIRECTIVES_1_0
|
86
|
-
SAFARI_10_DIRECTIVES = DIRECTIVES_2_0
|
87
|
-
|
88
|
-
FIREFOX_UNSUPPORTED_DIRECTIVES = [
|
89
|
-
BLOCK_ALL_MIXED_CONTENT,
|
90
|
-
CHILD_SRC,
|
91
|
-
WORKER_SRC,
|
92
|
-
PLUGIN_TYPES
|
93
|
-
].freeze
|
94
|
-
|
95
|
-
FIREFOX_46_DEPRECATED_DIRECTIVES = [
|
96
|
-
FRAME_SRC
|
97
|
-
].freeze
|
98
|
-
|
99
|
-
FIREFOX_46_UNSUPPORTED_DIRECTIVES = [
|
100
|
-
BLOCK_ALL_MIXED_CONTENT,
|
101
|
-
WORKER_SRC,
|
102
|
-
PLUGIN_TYPES
|
103
|
-
].freeze
|
104
|
-
|
105
|
-
FIREFOX_DIRECTIVES = (
|
106
|
-
DIRECTIVES_3_0 - FIREFOX_UNSUPPORTED_DIRECTIVES
|
107
|
-
).freeze
|
108
|
-
|
109
|
-
FIREFOX_46_DIRECTIVES = (
|
110
|
-
DIRECTIVES_3_0 - FIREFOX_46_UNSUPPORTED_DIRECTIVES - FIREFOX_46_DEPRECATED_DIRECTIVES
|
111
|
-
).freeze
|
112
|
-
|
113
|
-
CHROME_DIRECTIVES = (
|
114
|
-
DIRECTIVES_3_0
|
115
|
-
).freeze
|
116
|
-
|
117
84
|
ALL_DIRECTIVES = (DIRECTIVES_1_0 + DIRECTIVES_2_0 + DIRECTIVES_3_0).uniq.sort
|
118
85
|
|
119
86
|
# Think of default-src and report-uri as the beginning and end respectively,
|
120
87
|
# everything else is in between.
|
121
88
|
BODY_DIRECTIVES = ALL_DIRECTIVES - [DEFAULT_SRC, REPORT_URI]
|
122
89
|
|
123
|
-
VARIATIONS = {
|
124
|
-
"Chrome" => CHROME_DIRECTIVES,
|
125
|
-
"Opera" => CHROME_DIRECTIVES,
|
126
|
-
"Firefox" => FIREFOX_DIRECTIVES,
|
127
|
-
"FirefoxTransitional" => FIREFOX_46_DIRECTIVES,
|
128
|
-
"Safari" => SAFARI_DIRECTIVES,
|
129
|
-
"SafariTransitional" => SAFARI_10_DIRECTIVES,
|
130
|
-
"Edge" => EDGE_DIRECTIVES,
|
131
|
-
"Other" => CHROME_DIRECTIVES
|
132
|
-
}.freeze
|
133
|
-
|
134
|
-
OTHER = "Other".freeze
|
135
|
-
|
136
90
|
DIRECTIVE_VALUE_TYPES = {
|
137
91
|
BASE_URI => :source_list,
|
138
92
|
BLOCK_ALL_MIXED_CONTENT => :boolean,
|
@@ -199,9 +153,9 @@ module SecureHeaders
|
|
199
153
|
#
|
200
154
|
# Returns a default policy if no configuration is provided, or a
|
201
155
|
# header name and value based on the config.
|
202
|
-
def make_header(config
|
156
|
+
def make_header(config)
|
203
157
|
return if config.nil? || config == OPT_OUT
|
204
|
-
header = new(config
|
158
|
+
header = new(config)
|
205
159
|
[header.name, header.value]
|
206
160
|
end
|
207
161
|
|
@@ -303,17 +257,11 @@ module SecureHeaders
|
|
303
257
|
# Don't set a default if directive has an existing value
|
304
258
|
next if original[directive]
|
305
259
|
if FETCH_SOURCES.include?(directive)
|
306
|
-
original[directive] =
|
260
|
+
original[directive] = original[DEFAULT_SRC]
|
307
261
|
end
|
308
262
|
end
|
309
263
|
end
|
310
264
|
|
311
|
-
def default_for(directive, original)
|
312
|
-
return original[FRAME_SRC] if directive == CHILD_SRC && original[FRAME_SRC]
|
313
|
-
return original[CHILD_SRC] if directive == FRAME_SRC && original[CHILD_SRC]
|
314
|
-
original[DEFAULT_SRC]
|
315
|
-
end
|
316
|
-
|
317
265
|
def source_list?(directive)
|
318
266
|
DIRECTIVE_VALUE_TYPES[directive] == :source_list
|
319
267
|
end
|
data/secure_headers.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
Gem::Specification.new do |gem|
|
4
4
|
gem.name = "secure_headers"
|
5
|
-
gem.version = "6.0.0.
|
5
|
+
gem.version = "6.0.0.alpha03"
|
6
6
|
gem.authors = ["Neil Matatall"]
|
7
7
|
gem.email = ["neil.matatall@gmail.com"]
|
8
8
|
gem.description = "Manages application of security headers with many safe defaults."
|
@@ -16,5 +16,4 @@ Gem::Specification.new do |gem|
|
|
16
16
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
17
17
|
gem.require_paths = ["lib"]
|
18
18
|
gem.add_development_dependency "rake"
|
19
|
-
gem.add_dependency "useragent", ">= 0.15.0"
|
20
19
|
end
|
@@ -116,73 +116,10 @@ module SecureHeaders
|
|
116
116
|
ContentSecurityPolicy.new(default_src: %w('self'), frame_src: %w('self')).value
|
117
117
|
end
|
118
118
|
|
119
|
-
it "raises an error when child-src and frame-src are supplied but are not equal" do
|
120
|
-
expect {
|
121
|
-
ContentSecurityPolicy.new(default_src: %w('self'), child_src: %w(child-src.com), frame_src: %w(frame-src,com)).value
|
122
|
-
}.to raise_error(ArgumentError)
|
123
|
-
end
|
124
|
-
|
125
119
|
it "supports strict-dynamic" do
|
126
|
-
csp = ContentSecurityPolicy.new({default_src: %w('self'), script_src: [ContentSecurityPolicy::STRICT_DYNAMIC], script_nonce: 123456}
|
120
|
+
csp = ContentSecurityPolicy.new({default_src: %w('self'), script_src: [ContentSecurityPolicy::STRICT_DYNAMIC], script_nonce: 123456})
|
127
121
|
expect(csp.value).to eq("default-src 'self'; script-src 'strict-dynamic' 'nonce-123456' 'unsafe-inline'")
|
128
122
|
end
|
129
|
-
|
130
|
-
context "browser sniffing" do
|
131
|
-
let (:complex_opts) do
|
132
|
-
(ContentSecurityPolicy::ALL_DIRECTIVES - [:frame_src]).each_with_object({}) do |directive, hash|
|
133
|
-
hash[directive] = ["#{directive.to_s.gsub("_", "-")}.com"]
|
134
|
-
end.merge({
|
135
|
-
block_all_mixed_content: true,
|
136
|
-
upgrade_insecure_requests: true,
|
137
|
-
script_src: %w(script-src.com),
|
138
|
-
script_nonce: 123456,
|
139
|
-
sandbox: %w(allow-forms),
|
140
|
-
plugin_types: %w(application/pdf)
|
141
|
-
})
|
142
|
-
end
|
143
|
-
|
144
|
-
it "does not filter any directives for Chrome" do
|
145
|
-
policy = ContentSecurityPolicy.new(complex_opts, USER_AGENTS[:chrome])
|
146
|
-
expect(policy.value).to eq("default-src default-src.com; base-uri base-uri.com; block-all-mixed-content; child-src child-src.com; connect-src connect-src.com; font-src font-src.com; form-action form-action.com; frame-ancestors frame-ancestors.com; img-src img-src.com; manifest-src manifest-src.com; media-src media-src.com; object-src object-src.com; plugin-types application/pdf; sandbox allow-forms; script-src script-src.com 'nonce-123456' 'unsafe-inline'; style-src style-src.com; upgrade-insecure-requests; worker-src worker-src.com; report-uri report-uri.com")
|
147
|
-
end
|
148
|
-
|
149
|
-
it "does not filter any directives for Opera" do
|
150
|
-
policy = ContentSecurityPolicy.new(complex_opts, USER_AGENTS[:opera])
|
151
|
-
expect(policy.value).to eq("default-src default-src.com; base-uri base-uri.com; block-all-mixed-content; child-src child-src.com; connect-src connect-src.com; font-src font-src.com; form-action form-action.com; frame-ancestors frame-ancestors.com; img-src img-src.com; manifest-src manifest-src.com; media-src media-src.com; object-src object-src.com; plugin-types application/pdf; sandbox allow-forms; script-src script-src.com 'nonce-123456' 'unsafe-inline'; style-src style-src.com; upgrade-insecure-requests; worker-src worker-src.com; report-uri report-uri.com")
|
152
|
-
end
|
153
|
-
|
154
|
-
it "filters blocked-all-mixed-content, child-src, and plugin-types for firefox" do
|
155
|
-
policy = ContentSecurityPolicy.new(complex_opts, USER_AGENTS[:firefox])
|
156
|
-
expect(policy.value).to eq("default-src default-src.com; base-uri base-uri.com; connect-src connect-src.com; font-src font-src.com; form-action form-action.com; frame-ancestors frame-ancestors.com; frame-src child-src.com; img-src img-src.com; manifest-src manifest-src.com; media-src media-src.com; object-src object-src.com; sandbox allow-forms; script-src script-src.com 'nonce-123456' 'unsafe-inline'; style-src style-src.com; upgrade-insecure-requests; report-uri report-uri.com")
|
157
|
-
end
|
158
|
-
|
159
|
-
it "filters blocked-all-mixed-content, frame-src, and plugin-types for firefox 46 and higher" do
|
160
|
-
policy = ContentSecurityPolicy.new(complex_opts, USER_AGENTS[:firefox46])
|
161
|
-
expect(policy.value).to eq("default-src default-src.com; base-uri base-uri.com; child-src child-src.com; connect-src connect-src.com; font-src font-src.com; form-action form-action.com; frame-ancestors frame-ancestors.com; img-src img-src.com; manifest-src manifest-src.com; media-src media-src.com; object-src object-src.com; sandbox allow-forms; script-src script-src.com 'nonce-123456' 'unsafe-inline'; style-src style-src.com; upgrade-insecure-requests; report-uri report-uri.com")
|
162
|
-
end
|
163
|
-
|
164
|
-
it "child-src value is copied to frame-src, adds 'unsafe-inline', filters base-uri, blocked-all-mixed-content, upgrade-insecure-requests, child-src, form-action, frame-ancestors, hash sources, and plugin-types for Edge" do
|
165
|
-
policy = ContentSecurityPolicy.new(complex_opts, USER_AGENTS[:edge])
|
166
|
-
expect(policy.value).to eq("default-src default-src.com; connect-src connect-src.com; font-src font-src.com; frame-src child-src.com; img-src img-src.com; media-src media-src.com; object-src object-src.com; sandbox allow-forms; script-src script-src.com 'nonce-123456' 'unsafe-inline'; style-src style-src.com; report-uri report-uri.com")
|
167
|
-
end
|
168
|
-
|
169
|
-
it "child-src value is copied to frame-src, adds 'unsafe-inline', filters base-uri, blocked-all-mixed-content, upgrade-insecure-requests, child-src, form-action, frame-ancestors, hash sources, and plugin-types for safari" do
|
170
|
-
policy = ContentSecurityPolicy.new(complex_opts, USER_AGENTS[:safari6])
|
171
|
-
expect(policy.value).to eq("default-src default-src.com; connect-src connect-src.com; font-src font-src.com; frame-src child-src.com; img-src img-src.com; media-src media-src.com; object-src object-src.com; sandbox allow-forms; script-src script-src.com 'nonce-123456' 'unsafe-inline'; style-src style-src.com; report-uri report-uri.com")
|
172
|
-
end
|
173
|
-
|
174
|
-
it "adds 'unsafe-inline', filters blocked-all-mixed-content, upgrade-insecure-requests, and hash sources for safari 10 and higher" do
|
175
|
-
policy = ContentSecurityPolicy.new(complex_opts, USER_AGENTS[:safari10])
|
176
|
-
expect(policy.value).to eq("default-src default-src.com; base-uri base-uri.com; child-src child-src.com; connect-src connect-src.com; font-src font-src.com; form-action form-action.com; frame-ancestors frame-ancestors.com; img-src img-src.com; media-src media-src.com; object-src object-src.com; plugin-types application/pdf; sandbox allow-forms; script-src script-src.com 'nonce-123456' 'unsafe-inline'; style-src style-src.com; report-uri report-uri.com")
|
177
|
-
end
|
178
|
-
|
179
|
-
it "falls back to standard Firefox defaults when the useragent version is not present" do
|
180
|
-
ua = USER_AGENTS[:firefox].dup
|
181
|
-
allow(ua).to receive(:version).and_return(nil)
|
182
|
-
policy = ContentSecurityPolicy.new(complex_opts, ua)
|
183
|
-
expect(policy.value).to eq("default-src default-src.com; base-uri base-uri.com; connect-src connect-src.com; font-src font-src.com; form-action form-action.com; frame-ancestors frame-ancestors.com; frame-src child-src.com; img-src img-src.com; manifest-src manifest-src.com; media-src media-src.com; object-src object-src.com; sandbox allow-forms; script-src script-src.com 'nonce-123456' 'unsafe-inline'; style-src style-src.com; upgrade-insecure-requests; report-uri report-uri.com")
|
184
|
-
end
|
185
|
-
end
|
186
123
|
end
|
187
124
|
end
|
188
125
|
end
|
@@ -190,7 +190,7 @@ module SecureHeaders
|
|
190
190
|
report_uri = "https://report-uri.io/asdf"
|
191
191
|
default_policy = Configuration.dup
|
192
192
|
combined_config = ContentSecurityPolicy.combine_policies(default_policy.csp.to_h, report_uri: [report_uri])
|
193
|
-
csp = ContentSecurityPolicy.new(combined_config
|
193
|
+
csp = ContentSecurityPolicy.new(combined_config)
|
194
194
|
expect(csp.value).to include("report-uri #{report_uri}")
|
195
195
|
end
|
196
196
|
|
@@ -223,7 +223,7 @@ module SecureHeaders
|
|
223
223
|
end
|
224
224
|
default_policy = Configuration.dup
|
225
225
|
combined_config = ContentSecurityPolicy.combine_policies(default_policy.csp.to_h, report_only: true)
|
226
|
-
csp = ContentSecurityPolicy.new(combined_config
|
226
|
+
csp = ContentSecurityPolicy.new(combined_config)
|
227
227
|
expect(csp.name).to eq(ContentSecurityPolicyReportOnlyConfig::HEADER_NAME)
|
228
228
|
end
|
229
229
|
|
@@ -127,27 +127,6 @@ module SecureHeaders
|
|
127
127
|
expect(hash[XFrameOptions::HEADER_NAME]).to eq(XFrameOptions::SAMEORIGIN)
|
128
128
|
end
|
129
129
|
|
130
|
-
it "produces a UA-specific CSP when overriding (and busting the cache)" do
|
131
|
-
Configuration.default do |config|
|
132
|
-
config.csp = {
|
133
|
-
default_src: %w('self'),
|
134
|
-
script_src: %w('self'),
|
135
|
-
child_src: %w('self')
|
136
|
-
}
|
137
|
-
end
|
138
|
-
firefox_request = Rack::Request.new(request.env.merge("HTTP_USER_AGENT" => USER_AGENTS[:firefox]))
|
139
|
-
|
140
|
-
# append an unsupported directive
|
141
|
-
SecureHeaders.override_content_security_policy_directives(firefox_request, {plugin_types: %w(application/pdf)})
|
142
|
-
# append a supported directive
|
143
|
-
SecureHeaders.override_content_security_policy_directives(firefox_request, {script_src: %w('self')})
|
144
|
-
|
145
|
-
hash = SecureHeaders.header_hash_for(firefox_request)
|
146
|
-
|
147
|
-
# child-src is translated to frame-src
|
148
|
-
expect(hash[ContentSecurityPolicyConfig::HEADER_NAME]).to eq("default-src 'self'; frame-src 'self'; script-src 'self'")
|
149
|
-
end
|
150
|
-
|
151
130
|
it "produces a hash of headers with default config" do
|
152
131
|
Configuration.default
|
153
132
|
hash = SecureHeaders.header_hash_for(request)
|
@@ -197,22 +176,6 @@ module SecureHeaders
|
|
197
176
|
expect(hash[ContentSecurityPolicyConfig::HEADER_NAME]).to eq("default-src 'self'; script-src mycdn.com 'unsafe-inline' anothercdn.com")
|
198
177
|
end
|
199
178
|
|
200
|
-
it "child-src and frame-src must match" do
|
201
|
-
Configuration.default do |config|
|
202
|
-
config.csp = {
|
203
|
-
default_src: %w('self'),
|
204
|
-
frame_src: %w(frame_src.com),
|
205
|
-
script_src: %w('self')
|
206
|
-
}
|
207
|
-
end
|
208
|
-
|
209
|
-
SecureHeaders.append_content_security_policy_directives(chrome_request, child_src: %w(child_src.com))
|
210
|
-
|
211
|
-
expect {
|
212
|
-
SecureHeaders.header_hash_for(chrome_request)
|
213
|
-
}.to raise_error(ArgumentError)
|
214
|
-
end
|
215
|
-
|
216
179
|
it "supports named appends" do
|
217
180
|
Configuration.default do |config|
|
218
181
|
config.csp = {
|
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: 6.0.0.
|
4
|
+
version: 6.0.0.alpha03
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Neil Matatall
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-05-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -24,20 +24,6 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: useragent
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: 0.15.0
|
34
|
-
type: :runtime
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: 0.15.0
|
41
27
|
description: Manages application of security headers with many safe defaults.
|
42
28
|
email:
|
43
29
|
- neil.matatall@gmail.com
|