secure_headers 3.7.0 → 3.7.1

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: 591de0f41bc64b3520fbb2fdab9fc94b490d1604
4
- data.tar.gz: f836c5e63e4d054ff2ce3f1ec597bbd9cf67ed4b
3
+ metadata.gz: 95d8b4815c1f0553ff7a7d6ca32cc046aaf08009
4
+ data.tar.gz: 0f2f8a647f84de17c79d6369ace1ffbcaefdf089
5
5
  SHA512:
6
- metadata.gz: 5317d425d7c65dfc73b32703aae7e16e3a566b620b42e3233cd6dc7403a1a9842bb7dc00ffc5c13a86240c5a8abee3ae07fed0c73d4b06a06bcc11db39a79a20
7
- data.tar.gz: 154573bfb9112b4b1510abbde3f5eb1e85b709f7839ff4a6a547223e67e698ff014bb578f02b0e8775ee723016f5903e8cda38cb9846b24cafe3dc8e414bb007
6
+ metadata.gz: cbaedf0a0bf671e9a0e7454fa31e2a1bb3952481a21e37ee3cfeb0a6cc8833267af8781471413c10415736a792f50f7779accc5a18392b9139c4c311e47e6c32
7
+ data.tar.gz: dcd71e54dd3a2ea821e25e520f57be97aac4e00f8efd992bfc4cba84c5cf75e6777de38b710ef348ce62581e851deb498e2add4da06d6336ff4a4ca3b4b437be
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 3.7.1
2
+
3
+ Fix support for the sandbox attribute of CSP. `true` and `[]` represent the maximally restricted policy (`sandbox;`) and validate other values.
4
+
1
5
  ## 3.7.0
2
6
 
3
7
  Adds support for the `Expect-CT` header (@jacobbednarz: https://github.com/twitter/secureheaders/pull/322)
@@ -80,20 +80,55 @@ module SecureHeaders
80
80
  case DIRECTIVE_VALUE_TYPES[directive_name]
81
81
  when :boolean
82
82
  symbol_to_hyphen_case(directive_name) if @config.directive_value(directive_name)
83
- when :string
84
- [symbol_to_hyphen_case(directive_name), @config.directive_value(directive_name)].join(" ")
85
- else
86
- build_directive(directive_name)
83
+ when :sandbox_list
84
+ build_sandbox_list_directive(directive_name)
85
+ when :media_type_list
86
+ build_media_type_list_directive(directive_name)
87
+ when :source_list
88
+ build_source_list_directive(directive_name)
87
89
  end
88
90
  end.compact.join("; ")
89
91
  end
90
92
 
93
+ def build_sandbox_list_directive(directive)
94
+ return unless sandbox_list = @config.directive_value(directive)
95
+ max_strict_policy = case sandbox_list
96
+ when Array
97
+ sandbox_list.empty?
98
+ when true
99
+ true
100
+ else
101
+ false
102
+ end
103
+
104
+ # A maximally strict sandbox policy is just the `sandbox` directive,
105
+ # whith no configuraiton values.
106
+ if max_strict_policy
107
+ symbol_to_hyphen_case(directive)
108
+ elsif sandbox_list && sandbox_list.any?
109
+ [
110
+ symbol_to_hyphen_case(directive),
111
+ sandbox_list.uniq
112
+ ].join(" ")
113
+ end
114
+ end
115
+
116
+ def build_media_type_list_directive(directive)
117
+ return unless media_type_list = @config.directive_value(directive)
118
+ if media_type_list && media_type_list.any?
119
+ [
120
+ symbol_to_hyphen_case(directive),
121
+ media_type_list.uniq
122
+ ].join(" ")
123
+ end
124
+ end
125
+
91
126
  # Private: builds a string that represents one directive in a minified form.
92
127
  #
93
128
  # directive_name - a symbol representing the various ALL_DIRECTIVES
94
129
  #
95
130
  # Returns a string representing a directive.
96
- def build_directive(directive)
131
+ def build_source_list_directive(directive)
97
132
  source_list = case directive
98
133
  when :child_src
99
134
  if supported_directives.include?(:child_src)
@@ -109,18 +109,6 @@ module SecureHeaders
109
109
  # everything else is in between.
110
110
  BODY_DIRECTIVES = ALL_DIRECTIVES - [DEFAULT_SRC, REPORT_URI]
111
111
 
112
- # These are directives that do not inherit the default-src value. This is
113
- # useful when calling #combine_policies.
114
- NON_FETCH_SOURCES = [
115
- BASE_URI,
116
- FORM_ACTION,
117
- FRAME_ANCESTORS,
118
- PLUGIN_TYPES,
119
- REPORT_URI
120
- ]
121
-
122
- FETCH_SOURCES = ALL_DIRECTIVES - NON_FETCH_SOURCES
123
-
124
112
  VARIATIONS = {
125
113
  "Chrome" => CHROME_DIRECTIVES,
126
114
  "Opera" => CHROME_DIRECTIVES,
@@ -148,14 +136,30 @@ module SecureHeaders
148
136
  MANIFEST_SRC => :source_list,
149
137
  MEDIA_SRC => :source_list,
150
138
  OBJECT_SRC => :source_list,
151
- PLUGIN_TYPES => :source_list,
139
+ PLUGIN_TYPES => :media_type_list,
152
140
  REPORT_URI => :source_list,
153
- SANDBOX => :source_list,
141
+ SANDBOX => :sandbox_list,
154
142
  SCRIPT_SRC => :source_list,
155
143
  STYLE_SRC => :source_list,
156
144
  UPGRADE_INSECURE_REQUESTS => :boolean
157
145
  }.freeze
158
146
 
147
+ # These are directives that don't have use a source list, and hence do not
148
+ # inherit the default-src value.
149
+ NON_SOURCE_LIST_SOURCES = DIRECTIVE_VALUE_TYPES.select do |_, type|
150
+ type != :source_list
151
+ end.keys.freeze
152
+
153
+ # These are directives that take a source list, but that do not inherit
154
+ # the default-src value.
155
+ NON_FETCH_SOURCES = [
156
+ BASE_URI,
157
+ FORM_ACTION,
158
+ FRAME_ANCESTORS,
159
+ REPORT_URI
160
+ ]
161
+
162
+ FETCH_SOURCES = ALL_DIRECTIVES - NON_FETCH_SOURCES - NON_SOURCE_LIST_SOURCES
159
163
 
160
164
  STAR_REGEXP = Regexp.new(Regexp.escape(STAR))
161
165
  HTTP_SCHEME_REGEX = %r{\Ahttps?://}
@@ -253,7 +257,7 @@ module SecureHeaders
253
257
  # when each hash contains a value for a given key.
254
258
  def merge_policy_additions(original, additions)
255
259
  original.merge(additions) do |directive, lhs, rhs|
256
- if source_list?(directive)
260
+ if list_directive?(directive)
257
261
  (lhs.to_a + rhs.to_a).compact.uniq
258
262
  else
259
263
  rhs
@@ -261,20 +265,27 @@ module SecureHeaders
261
265
  end.reject { |_, value| value.nil? || value == [] } # this mess prevents us from adding empty directives.
262
266
  end
263
267
 
268
+ # Returns True if a directive expects a list of values and False otherwise.
269
+ def list_directive?(directive)
270
+ source_list?(directive) ||
271
+ sandbox_list?(directive) ||
272
+ media_type_list?(directive)
273
+ end
274
+
264
275
  # For each directive in additions that does not exist in the original config,
265
276
  # copy the default-src value to the original config. This modifies the original hash.
266
277
  def populate_fetch_source_with_default!(original, additions)
267
278
  # in case we would be appending to an empty directive, fill it with the default-src value
268
279
  additions.each_key do |directive|
269
- if !original[directive] && ((source_list?(directive) && FETCH_SOURCES.include?(directive)) || nonce_added?(original, additions))
270
- if nonce_added?(original, additions)
271
- inferred_directive = directive.to_s.gsub(/_nonce/, "_src").to_sym
272
- unless original[inferred_directive] || NON_FETCH_SOURCES.include?(inferred_directive)
273
- original[inferred_directive] = default_for(directive, original)
274
- end
275
- else
276
- original[directive] = default_for(directive, original)
277
- end
280
+ directive = if directive.to_s.end_with?("_nonce")
281
+ directive.to_s.gsub(/_nonce/, "_src").to_sym
282
+ else
283
+ directive
284
+ end
285
+ # Don't set a default if directive has an existing value
286
+ next if original[directive]
287
+ if FETCH_SOURCES.include?(directive)
288
+ original[directive] = default_for(directive, original)
278
289
  end
279
290
  end
280
291
  end
@@ -285,45 +296,77 @@ module SecureHeaders
285
296
  original[DEFAULT_SRC]
286
297
  end
287
298
 
288
- def nonce_added?(original, additions)
289
- [:script_nonce, :style_nonce].each do |nonce|
290
- if additions[nonce] && !original[nonce]
291
- return true
292
- end
293
- end
294
- end
295
-
296
299
  def source_list?(directive)
297
300
  DIRECTIVE_VALUE_TYPES[directive] == :source_list
298
301
  end
299
302
 
303
+ def sandbox_list?(directive)
304
+ DIRECTIVE_VALUE_TYPES[directive] == :sandbox_list
305
+ end
306
+
307
+ def media_type_list?(directive)
308
+ DIRECTIVE_VALUE_TYPES[directive] == :media_type_list
309
+ end
310
+
300
311
  # Private: Validates that the configuration has a valid type, or that it is a valid
301
312
  # source expression.
302
- def validate_directive!(directive, source_expression)
313
+ def validate_directive!(directive, value)
314
+ ensure_valid_directive!(directive)
303
315
  case ContentSecurityPolicy::DIRECTIVE_VALUE_TYPES[directive]
304
316
  when :boolean
305
- unless boolean?(source_expression)
306
- raise ContentSecurityPolicyConfigError.new("#{directive} must be a boolean value")
307
- end
308
- when :string
309
- unless source_expression.is_a?(String)
310
- raise ContentSecurityPolicyConfigError.new("#{directive} Must be a string. Found #{config.class}: #{config} value")
317
+ unless boolean?(value)
318
+ raise ContentSecurityPolicyConfigError.new("#{directive} must be a boolean. Found #{value.class} value")
311
319
  end
320
+ when :sandbox_list
321
+ validate_sandbox_expression!(directive, value)
322
+ when :media_type_list
323
+ validate_media_type_expression!(directive, value)
324
+ when :source_list
325
+ validate_source_expression!(directive, value)
312
326
  else
313
- validate_source_expression!(directive, source_expression)
327
+ raise ContentSecurityPolicyConfigError.new("Unknown directive #{directive}")
328
+ end
329
+ end
330
+
331
+ # Private: validates that a sandbox token expression:
332
+ # 1. is an array of strings or optionally `true` (to enable maximal sandboxing)
333
+ # 2. For arrays, each element is of the form allow-*
334
+ def validate_sandbox_expression!(directive, sandbox_token_expression)
335
+ # We support sandbox: true to indicate a maximally secure sandbox.
336
+ return if boolean?(sandbox_token_expression) && sandbox_token_expression == true
337
+ ensure_array_of_strings!(directive, sandbox_token_expression)
338
+ valid = sandbox_token_expression.compact.all? do |v|
339
+ v.is_a?(String) && v.start_with?("allow-")
340
+ end
341
+ if !valid
342
+ raise ContentSecurityPolicyConfigError.new("#{directive} must be True or an array of zero or more sandbox token strings (ex. allow-forms)")
343
+ end
344
+ end
345
+
346
+ # Private: validates that a media type expression:
347
+ # 1. is an array of strings
348
+ # 2. each element is of the form type/subtype
349
+ def validate_media_type_expression!(directive, media_type_expression)
350
+ ensure_array_of_strings!(directive, media_type_expression)
351
+ valid = media_type_expression.compact.all? do |v|
352
+ # All media types are of the form: <type from RFC 2045> "/" <subtype from RFC 2045>.
353
+ v =~ /\A.+\/.+\z/
354
+ end
355
+ if !valid
356
+ raise ContentSecurityPolicyConfigError.new("#{directive} must be an array of valid media types (ex. application/pdf)")
314
357
  end
315
358
  end
316
359
 
317
360
  # Private: validates that a source expression:
318
- # 1. has a valid name
319
- # 2. is an array of strings
320
- # 3. does not contain any depreated, now invalid values (inline, eval, self, none)
361
+ # 1. is an array of strings
362
+ # 2. does not contain any deprecated, now invalid values (inline, eval, self, none)
321
363
  #
322
364
  # Does not validate the invididual values of the source expression (e.g.
323
365
  # script_src => h*t*t*p: will not raise an exception)
324
366
  def validate_source_expression!(directive, source_expression)
325
- ensure_valid_directive!(directive)
326
- ensure_array_of_strings!(directive, source_expression)
367
+ if source_expression != OPT_OUT
368
+ ensure_array_of_strings!(directive, source_expression)
369
+ end
327
370
  ensure_valid_sources!(directive, source_expression)
328
371
  end
329
372
 
@@ -333,8 +376,8 @@ module SecureHeaders
333
376
  end
334
377
  end
335
378
 
336
- def ensure_array_of_strings!(directive, source_expression)
337
- unless source_expression.is_a?(Array) && source_expression.compact.all? { |v| v.is_a?(String) }
379
+ def ensure_array_of_strings!(directive, value)
380
+ if (!value.is_a?(Array) || !value.compact.all? { |v| v.is_a?(String) })
338
381
  raise ContentSecurityPolicyConfigError.new("#{directive} must be an array of strings")
339
382
  end
340
383
  end
@@ -1,7 +1,7 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  Gem::Specification.new do |gem|
3
3
  gem.name = "secure_headers"
4
- gem.version = "3.7.0"
4
+ gem.version = "3.7.1"
5
5
  gem.authors = ["Neil Matatall"]
6
6
  gem.email = ["neil.matatall@gmail.com"]
7
7
  gem.description = 'Manages application of security headers with many safe defaults.'
@@ -86,6 +86,21 @@ module SecureHeaders
86
86
  expect(csp.value).to eq("default-src example.org")
87
87
  end
88
88
 
89
+ it "creates maximally strict sandbox policy when passed no sandbox token values" do
90
+ csp = ContentSecurityPolicy.new(default_src: %w(example.org), sandbox: [])
91
+ expect(csp.value).to eq("default-src example.org; sandbox")
92
+ end
93
+
94
+ it "creates maximally strict sandbox policy when passed true" do
95
+ csp = ContentSecurityPolicy.new(default_src: %w(example.org), sandbox: true)
96
+ expect(csp.value).to eq("default-src example.org; sandbox")
97
+ end
98
+
99
+ it "creates sandbox policy when passed valid sandbox token values" do
100
+ csp = ContentSecurityPolicy.new(default_src: %w(example.org), sandbox: %w(allow-forms allow-scripts))
101
+ expect(csp.value).to eq("default-src example.org; sandbox allow-forms allow-scripts")
102
+ end
103
+
89
104
  it "does not emit a warning when using frame-src" do
90
105
  expect(Kernel).to_not receive(:warn)
91
106
  ContentSecurityPolicy.new(default_src: %w('self'), frame_src: %w('self')).value
@@ -120,50 +135,52 @@ module SecureHeaders
120
135
  block_all_mixed_content: true,
121
136
  upgrade_insecure_requests: true,
122
137
  script_src: %w(script-src.com),
123
- script_nonce: 123456
138
+ script_nonce: 123456,
139
+ sandbox: %w(allow-forms),
140
+ plugin_types: %w(application/pdf)
124
141
  })
125
142
  end
126
143
 
127
144
  it "does not filter any directives for Chrome" do
128
145
  policy = ContentSecurityPolicy.new(complex_opts, USER_AGENTS[:chrome])
129
- 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 plugin-types.com; sandbox sandbox.com; script-src script-src.com 'nonce-123456'; style-src style-src.com; upgrade-insecure-requests; report-uri report-uri.com")
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'; style-src style-src.com; upgrade-insecure-requests; report-uri report-uri.com")
130
147
  end
131
148
 
132
149
  it "does not filter any directives for Opera" do
133
150
  policy = ContentSecurityPolicy.new(complex_opts, USER_AGENTS[:opera])
134
- 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 plugin-types.com; sandbox sandbox.com; script-src script-src.com 'nonce-123456'; style-src style-src.com; upgrade-insecure-requests; report-uri report-uri.com")
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'; style-src style-src.com; upgrade-insecure-requests; report-uri report-uri.com")
135
152
  end
136
153
 
137
154
  it "filters blocked-all-mixed-content, child-src, and plugin-types for firefox" do
138
155
  policy = ContentSecurityPolicy.new(complex_opts, USER_AGENTS[:firefox])
139
- 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 sandbox.com; script-src script-src.com 'nonce-123456'; style-src style-src.com; upgrade-insecure-requests; report-uri report-uri.com")
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'; style-src style-src.com; upgrade-insecure-requests; report-uri report-uri.com")
140
157
  end
141
158
 
142
159
  it "filters blocked-all-mixed-content, frame-src, and plugin-types for firefox 46 and higher" do
143
160
  policy = ContentSecurityPolicy.new(complex_opts, USER_AGENTS[:firefox46])
144
- 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 sandbox.com; script-src script-src.com 'nonce-123456'; style-src style-src.com; upgrade-insecure-requests; report-uri report-uri.com")
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'; style-src style-src.com; upgrade-insecure-requests; report-uri report-uri.com")
145
162
  end
146
163
 
147
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, nonce sources, hash sources, and plugin-types for Edge" do
148
165
  policy = ContentSecurityPolicy.new(complex_opts, USER_AGENTS[:edge])
149
- 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 sandbox.com; script-src script-src.com 'unsafe-inline'; style-src style-src.com; report-uri report-uri.com")
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 'unsafe-inline'; style-src style-src.com; report-uri report-uri.com")
150
167
  end
151
168
 
152
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, nonce sources, hash sources, and plugin-types for safari" do
153
170
  policy = ContentSecurityPolicy.new(complex_opts, USER_AGENTS[:safari6])
154
- 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 sandbox.com; script-src script-src.com 'unsafe-inline'; style-src style-src.com; report-uri report-uri.com")
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 'unsafe-inline'; style-src style-src.com; report-uri report-uri.com")
155
172
  end
156
173
 
157
174
  it "adds 'unsafe-inline', filters blocked-all-mixed-content, upgrade-insecure-requests, nonce sources, and hash sources for safari 10 and higher" do
158
175
  policy = ContentSecurityPolicy.new(complex_opts, USER_AGENTS[:safari10])
159
- 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 plugin-types.com; sandbox sandbox.com; script-src script-src.com 'nonce-123456'; style-src style-src.com; report-uri report-uri.com")
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'; style-src style-src.com; report-uri report-uri.com")
160
177
  end
161
178
 
162
179
  it "falls back to standard Firefox defaults when the useragent version is not present" do
163
180
  ua = USER_AGENTS[:firefox].dup
164
181
  allow(ua).to receive(:version).and_return(nil)
165
182
  policy = ContentSecurityPolicy.new(complex_opts, ua)
166
- 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 sandbox.com; script-src script-src.com 'nonce-123456'; style-src style-src.com; upgrade-insecure-requests; report-uri report-uri.com")
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'; style-src style-src.com; upgrade-insecure-requests; report-uri report-uri.com")
167
184
  end
168
185
  end
169
186
  end
@@ -98,6 +98,36 @@ module SecureHeaders
98
98
  ContentSecurityPolicy.validate_config!(ContentSecurityPolicyConfig.new(default_src: %w(self none inline eval)))
99
99
  end.to raise_error(ContentSecurityPolicyConfigError)
100
100
  end
101
+
102
+ it "rejects anything not of the form allow-* as a sandbox value" do
103
+ expect do
104
+ ContentSecurityPolicy.validate_config!(ContentSecurityPolicyConfig.new(default_opts.merge(sandbox: ["steve"])))
105
+ end.to raise_error(ContentSecurityPolicyConfigError)
106
+ end
107
+
108
+ it "accepts anything of the form allow-* as a sandbox value " do
109
+ expect do
110
+ ContentSecurityPolicy.validate_config!(ContentSecurityPolicyConfig.new(default_opts.merge(sandbox: ["allow-foo"])))
111
+ end.to_not raise_error
112
+ end
113
+
114
+ it "accepts true as a sandbox policy" do
115
+ expect do
116
+ ContentSecurityPolicy.validate_config!(ContentSecurityPolicyConfig.new(default_opts.merge(sandbox: true)))
117
+ end.to_not raise_error
118
+ end
119
+
120
+ it "rejects anything not of the form type/subtype as a plugin-type value" do
121
+ expect do
122
+ ContentSecurityPolicy.validate_config!(ContentSecurityPolicyConfig.new(default_opts.merge(plugin_types: ["steve"])))
123
+ end.to raise_error(ContentSecurityPolicyConfigError)
124
+ end
125
+
126
+ it "accepts anything of the form type/subtype as a plugin-type value " do
127
+ expect do
128
+ ContentSecurityPolicy.validate_config!(ContentSecurityPolicyConfig.new(default_opts.merge(plugin_types: ["application/pdf"])))
129
+ end.to_not raise_error
130
+ end
101
131
  end
102
132
 
103
133
  describe "#combine_policies" do
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: 3.7.0
4
+ version: 3.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Neil Matatall
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-08-25 00:00:00.000000000 Z
11
+ date: 2017-09-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake