secure_headers 3.5.0 → 3.6.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f47871f10c97316165d3f4230ddae85935d9a736
4
- data.tar.gz: f5777312e07643e054d48b4121ba30a905aab4dd
3
+ metadata.gz: 7585a939ce1ded2d2226ba1d1503a5f0dca3eb49
4
+ data.tar.gz: 3762611d81eb31f24cdfd04a609d7aaed5a62182
5
5
  SHA512:
6
- metadata.gz: 8516799304bf21ea8d67aace99325df8c34d1e3d72082b44ad4a80c658ddc9cee6e4a04fc8202ac062044c0abbc91ce870fc26a472960f390fe359670f7362cf
7
- data.tar.gz: d4fc7f5482fc8e904ce3ea80340da5c5426b87c88bbb8f669af9e050b212a1189b997de0c3c6bdc9a3b4df58c69efa54598ea40caaf56eb9bc69a80722029f8c
6
+ metadata.gz: 4ba111dea43dd24b25567ff18e98fb1de8ad5f5a04566a9390e9a20e9c405571038960bd3dca417d225f58deea82214e27d8381448c887607db2883cd71b6dda
7
+ data.tar.gz: 7dd6cf414c1e3ed0814b5095730cd98ee77259c3560dc7a9371754dbbbff837f44a7cc93d664f85d7317fb6f633f0b2a5d8145f7d7fac5833a5dfc83fa0b4a72
data/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ ## 3.6.0
2
+
3
+ Add support for the clear-site-data header
4
+
5
+ ## 3.5.1
6
+
7
+ * Fix bug that can occur when useragent library version is older, resulting in a nil version sometimes.
8
+ * Add constant for `strict-dynamic`
9
+
1
10
  ## 3.5.0
2
11
 
3
12
  This release adds support for setting two CSP headers (enforced/report-only) and management around them.
data/README.md CHANGED
@@ -7,6 +7,9 @@
7
7
 
8
8
  The gem will automatically apply several headers that are related to security. This includes:
9
9
  - Content Security Policy (CSP) - Helps detect/prevent XSS, mixed-content, and other classes of attack. [CSP 2 Specification](http://www.w3.org/TR/CSP2/)
10
+ - https://csp.withgoogle.com
11
+ - https://csp.withgoogle.com/docs/strict-csp.html
12
+ - https://csp-evaluator.withgoogle.com
10
13
  - HTTP Strict Transport Security (HSTS) - Ensures the browser never visits the http version of a website. Protects from SSLStrip/Firesheep attacks. [HSTS Specification](https://tools.ietf.org/html/rfc6797)
11
14
  - X-Frame-Options (XFO) - Prevents your content from being framed and potentially clickjacked. [X-Frame-Options Specification](https://tools.ietf.org/html/rfc7034)
12
15
  - X-XSS-Protection - [Cross site scripting heuristic filter for IE/Chrome](https://msdn.microsoft.com/en-us/library/dd565647\(v=vs.85\).aspx)
@@ -15,11 +18,35 @@ The gem will automatically apply several headers that are related to security.
15
18
  - 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)
16
19
  - Referrer-Policy - [Referrer Policy draft](https://w3c.github.io/webappsec-referrer-policy/)
17
20
  - Public Key Pinning - Pin certificate fingerprints in the browser to prevent man-in-the-middle attacks due to compromised Certificate Authorities. [Public Key Pinning Specification](https://tools.ietf.org/html/rfc7469)
21
+ - Clear-Site-Data - Clearing browser data for origin. [Clear-Site-Data specification](https://www.w3.org/TR/clear-site-data/).
18
22
 
19
23
  It can also mark all http cookies with the Secure, HttpOnly and SameSite attributes (when configured to do so).
20
24
 
21
25
  `secure_headers` is a library with a global config, per request overrides, and rack middleware that enables you customize your application settings.
22
26
 
27
+ ## Documentation
28
+
29
+ - [Named overrides and appends](docs/named_overrides_and_appends.md)
30
+ - [Per action configuration](docs/per_action_configuration.md)
31
+ - [Cookies](docs/cookies.md)
32
+ - [HPKP](docs/HPKP.md)
33
+ - [Hashes](docs/hashes.md)
34
+ - [Sinatra Config](docs/sinatra.md)
35
+
36
+ ## Getting Started
37
+
38
+ ### Rails 3+
39
+
40
+ For Rails 3+ applications, `secure_headers` has a `railtie` that should automatically include the middleware. If for some reason the middleware is not being included follow the instructions for Rails 2.
41
+
42
+ ### Rails 2
43
+
44
+ For Rails 2 or non-rails applications, an explicit statement is required to use the middleware component.
45
+
46
+ ```ruby
47
+ use SecureHeaders::Middleware
48
+ ```
49
+
23
50
  ## Configuration
24
51
 
25
52
  If you do not supply a `default` configuration, exceptions will be raised. If you would like to use a default configuration (which is fairly locked down), just call `SecureHeaders::Configuration.default` without any arguments or block.
@@ -42,6 +69,12 @@ SecureHeaders::Configuration.default do |config|
42
69
  config.x_download_options = "noopen"
43
70
  config.x_permitted_cross_domain_policies = "none"
44
71
  config.referrer_policy = "origin-when-cross-origin"
72
+ config.clear_site_data = [
73
+ "cache",
74
+ "cookies",
75
+ "storage",
76
+ "executionContexts"
77
+ ]
45
78
  config.csp = {
46
79
  # "meta" values. these will shaped the header, but the values are not included in the header.
47
80
  report_only: true, # default: false [DEPRECATED from 3.5.0: instead, configure csp_report_only]
@@ -83,17 +116,9 @@ SecureHeaders::Configuration.default do |config|
83
116
  end
84
117
  ```
85
118
 
86
- ### rails 2
87
-
88
- For rails 3+ applications, `secure_headers` has a `railtie` that should automatically include the middleware. For rails 2 or non-rails applications, an explicit statement is required to use the middleware component.
89
-
90
- ```ruby
91
- use SecureHeaders::Middleware
92
- ```
93
-
94
119
  ## Default values
95
120
 
96
- All headers except for PublicKeyPins have a default value. See the [corresponding classes for their defaults](https://github.com/twitter/secureheaders/tree/master/lib/secure_headers/headers). The default set of headers is:
121
+ All headers except for PublicKeyPins and ClearSiteData have a default value. The default set of headers is:
97
122
 
98
123
  ```
99
124
  Content-Security-Policy: default-src 'self' https:; font-src 'self' https: data:; img-src 'self' https: data:; object-src 'none'; script-src https:; style-src 'self' https: 'unsafe-inline'
@@ -118,379 +143,6 @@ Configuration.default do |config|
118
143
  end
119
144
  ```
120
145
 
121
- ## Named Appends
122
-
123
- Named Appends are blocks of code that can be reused and composed during requests. e.g. If a certain partial is rendered conditionally, and the csp needs to be adjusted for that partial, you can create a named append for that situation. The value returned by the block will be passed into `append_content_security_policy_directives`. The current request object is passed as an argument to the block for even more flexibility.
124
-
125
- ```ruby
126
- def show
127
- if include_widget?
128
- @widget = widget.render
129
- use_content_security_policy_named_append(:widget_partial)
130
- end
131
- end
132
-
133
-
134
- SecureHeaders::Configuration.named_append(:widget_partial) do |request|
135
- SecureHeaders.override_x_frame_options(request, "DENY")
136
- if request.controller_instance.current_user.in_test_bucket?
137
- { child_src: %w(beta.thirdpartyhost.com) }
138
- else
139
- { child_src: %w(thirdpartyhost.com) }
140
- end
141
- end
142
- ```
143
-
144
- You can use as many named appends as you would like per request, but be careful because order of inclusion matters. Consider the following:
145
-
146
- ```ruby
147
- SecureHeader::Configuration.default do |config|
148
- config.csp = { default_src: %w('self')}
149
- end
150
-
151
- SecureHeaders::Configuration.named_append(:A) do |request|
152
- { default_src: %w(myhost.com) }
153
- end
154
-
155
- SecureHeaders::Configuration.named_append(:B) do |request|
156
- { script_src: %w('unsafe-eval') }
157
- end
158
- ```
159
-
160
- The following code will produce different policies due to the way policies are normalized (e.g. providing a previously undefined directive that inherits from `default-src`, removing host source values when `*` is provided. Removing `'none'` when additional values are present, etc.):
161
-
162
- ```ruby
163
- def index
164
- use_content_security_policy_named_append(:A)
165
- use_content_security_policy_named_append(:B)
166
- # produces default-src 'self' myhost.com; script-src 'self' myhost.com 'unsafe-eval';
167
- end
168
-
169
- def show
170
- use_content_security_policy_named_append(:B)
171
- use_content_security_policy_named_append(:A)
172
- # produces default-src 'self' myhost.com; script-src 'self' 'unsafe-eval';
173
- end
174
- ```
175
-
176
-
177
- ## Named overrides
178
-
179
- Named overrides serve two purposes:
180
-
181
- * To be able to refer to a configuration by simple name.
182
- * By precomputing the headers for a named configuration, the headers generated once and reused over every request.
183
-
184
- To use a named override, drop a `SecureHeaders::Configuration.override` block **outside** of method definitions and then declare which named override you'd like to use. You can even override an override.
185
-
186
- ```ruby
187
- class ApplicationController < ActionController::Base
188
- SecureHeaders::Configuration.default do |config|
189
- config.csp = {
190
- default_src: %w('self'),
191
- script_src: %w(example.org)
192
- }
193
- end
194
-
195
- # override default configuration
196
- SecureHeaders::Configuration.override(:script_from_otherdomain_com) do |config|
197
- config.csp[:script_src] << "otherdomain.com"
198
- end
199
-
200
- # overrides the :script_from_otherdomain_com configuration
201
- SecureHeaders::Configuration.override(:another_config, :script_from_otherdomain_com) do |config|
202
- config.csp[:script_src] << "evenanotherdomain.com"
203
- end
204
- end
205
-
206
- class MyController < ApplicationController
207
- def index
208
- # Produces default-src 'self'; script-src example.org otherdomain.com
209
- use_secure_headers_override(:script_from_otherdomain_com)
210
- end
211
-
212
- def show
213
- # Produces default-src 'self'; script-src example.org otherdomain.org evenanotherdomain.com
214
- use_secure_headers_override(:another_config)
215
- end
216
- end
217
- ```
218
-
219
- By default, a no-op configuration is provided. No headers will be set when this default override is used.
220
-
221
- ```ruby
222
- class MyController < ApplicationController
223
- def index
224
- SecureHeaders.opt_out_of_all_protection(request)
225
- end
226
- end
227
- ```
228
-
229
- ## Per-action configuration
230
-
231
- You can override the settings for a given action by producing a temporary override. Be aware that because of the dynamic nature of the value, the header values will be computed per request.
232
-
233
- ```ruby
234
- # Given a config of:
235
- ::SecureHeaders::Configuration.default do |config|
236
- config.csp = {
237
- default_src: %w('self'),
238
- script_src: %w('self')
239
- }
240
- end
241
-
242
- class MyController < ApplicationController
243
- def index
244
- # Append value to the source list, override 'none' values
245
- # Produces: default-src 'self'; script-src 'self' s3.amazonaws.com; object-src 'self' www.youtube.com
246
- append_content_security_policy_directives(script_src: %w(s3.amazonaws.com), object_src: %w('self' www.youtube.com))
247
-
248
- # Overrides the previously set source list, override 'none' values
249
- # Produces: default-src 'self'; script-src s3.amazonaws.com; object-src 'self'
250
- override_content_security_policy_directives(script_src: %w(s3.amazonaws.com), object_src: %w('self'))
251
-
252
- # Global settings default to "sameorigin"
253
- override_x_frame_options("DENY")
254
- end
255
- ```
256
-
257
- The following methods are available as controller instance methods. They are also available as class methods, but require you to pass in the `request` object.
258
- * `append_content_security_policy_directives(hash)`: appends each value to the corresponding CSP app-wide configuration.
259
- * `override_content_security_policy_directives(hash)`: merges the hash into the app-wide configuration, overwriting any previous config
260
- * `override_x_frame_options(value)`: sets the `X-Frame-Options header` to `value`
261
-
262
- ## Appending / overriding Content Security Policy
263
-
264
- When manipulating content security policy, there are a few things to consider. The default header value is `default-src https:` which corresponds to a default configuration of `{ default_src: %w(https:)}`.
265
-
266
- #### Append to the policy with a directive other than `default_src`
267
-
268
- The value of `default_src` is joined with the addition if the it is a [fetch directive](https://w3c.github.io/webappsec-csp/#directives-fetch). Note the `https:` is carried over from the `default-src` config. If you do not want this, use `override_content_security_policy_directives` instead. To illustrate:
269
-
270
- ```ruby
271
- ::SecureHeaders::Configuration.default do |config|
272
- config.csp = {
273
- default_src: %w('self')
274
- }
275
- end
276
- ```
277
-
278
- Code | Result
279
- ------------- | -------------
280
- `append_content_security_policy_directives(script_src: %w(mycdn.com))` | `default-src 'self'; script-src 'self' mycdn.com`
281
- `override_content_security_policy_directives(script_src: %w(mycdn.com))` | `default-src 'self'; script-src mycdn.com`
282
-
283
- #### Nonce
284
-
285
- You can use a view helper to automatically add nonces to script tags:
286
-
287
- ```erb
288
- <%= nonced_javascript_tag do %>
289
- console.log("nonced!");
290
- <% end %>
291
-
292
- <%= nonced_style_tag do %>
293
- body {
294
- background-color: black;
295
- }
296
- <% end %>
297
- ```
298
-
299
- becomes:
300
-
301
- ```html
302
- <script nonce="/jRAxuLJsDXAxqhNBB7gg7h55KETtDQBXe4ZL+xIXwI=">
303
- console.log("nonced!")
304
- </script>
305
- <style nonce="/jRAxuLJsDXAxqhNBB7gg7h55KETtDQBXe4ZL+xIXwI=">
306
- body {
307
- background-color: black;
308
- }
309
- </style>
310
- ```
311
-
312
- ```
313
-
314
- Content-Security-Policy: ...
315
- script-src 'nonce-/jRAxuLJsDXAxqhNBB7gg7h55KETtDQBXe4ZL+xIXwI=' ...;
316
- style-src 'nonce-/jRAxuLJsDXAxqhNBB7gg7h55KETtDQBXe4ZL+xIXwI=' ...;
317
- ```
318
-
319
- `script`/`style-nonce` can be used to whitelist inline content. To do this, call the `content_security_policy_script_nonce` or `content_security_policy_style_nonce` then set the nonce attributes on the various tags.
320
-
321
- ```erb
322
- <script nonce="<%= content_security_policy_script_nonce %>">
323
- console.log("whitelisted, will execute")
324
- </script>
325
-
326
- <script nonce="lol">
327
- console.log("won't execute, not whitelisted")
328
- </script>
329
-
330
- <script>
331
- console.log("won't execute, not whitelisted")
332
- </script>
333
- ```
334
-
335
- #### Hash
336
-
337
- `script`/`style-src` hashes can be used to whitelist inline content that is static. This has the benefit of allowing inline content without opening up the possibility of dynamic javascript like you would with a `nonce`.
338
-
339
- You can add hash sources directly to your policy :
340
-
341
- ```ruby
342
- ::SecureHeaders::Configuration.default do |config|
343
- config.csp = {
344
- default_src: %w('self')
345
-
346
- # this is a made up value but browsers will show the expected hash in the console.
347
- script_src: %w(sha256-123456)
348
- }
349
- end
350
- ```
351
-
352
- You can also use the automated inline script detection/collection/computation of hash source values in your app.
353
-
354
- ```bash
355
- rake secure_headers:generate_hashes
356
- ```
357
-
358
- This will generate a file (`config/config/secure_headers_generated_hashes.yml` by default, you can override by setting `ENV["secure_headers_generated_hashes_file"]`) containing a mapping of file names with the array of hash values found on that page. When ActionView renders a given file, we check if there are any known hashes for that given file. If so, they are added as values to the header.
359
-
360
- ```yaml
361
- ---
362
- scripts:
363
- app/views/asdfs/index.html.erb:
364
- - "'sha256-yktKiAsZWmc8WpOyhnmhQoDf9G2dAZvuBBC+V0LGQhg='"
365
- styles:
366
- app/views/asdfs/index.html.erb:
367
- - "'sha256-SLp6LO3rrKDJwsG9uJUxZapb4Wp2Zhj6Bu3l+d9rnAY='"
368
- - "'sha256-HSGHqlRoKmHAGTAJ2Rq0piXX4CnEbOl1ArNd6ejp2TE='"
369
- ```
370
-
371
- ##### Helpers
372
-
373
- **This will not compute dynamic hashes** by design. The output of both helpers will be a plain `script`/`style` tag without modification and the known hashes for a given file will be added to `script-src`/`style-src` when `hashed_javascript_tag` and `hashed_style_tag` are used. You can use `raise_error_on_unrecognized_hash = true` to be extra paranoid that you have precomputed hash values for all of your inline content. By default, this will raise an error in non-production environments.
374
-
375
- ```erb
376
- <%= hashed_style_tag do %>
377
- body {
378
- background-color: black;
379
- }
380
- <% end %>
381
-
382
- <%= hashed_style_tag do %>
383
- body {
384
- font-size: 30px;
385
- font-color: green;
386
- }
387
- <% end %>
388
-
389
- <%= hashed_javascript_tag do %>
390
- console.log(1)
391
- <% end %>
392
- ```
393
-
394
- ```
395
- Content-Security-Policy: ...
396
- script-src 'sha256-yktKiAsZWmc8WpOyhnmhQoDf9G2dAZvuBBC+V0LGQhg=' ... ;
397
- style-src 'sha256-SLp6LO3rrKDJwsG9uJUxZapb4Wp2Zhj6Bu3l+d9rnAY=' 'sha256-HSGHqlRoKmHAGTAJ2Rq0piXX4CnEbOl1ArNd6ejp2TE=' ...;
398
- ```
399
-
400
- ### Public Key Pins
401
-
402
- 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.
403
-
404
- ```ruby
405
- config.hpkp = {
406
- max_age: 60.days.to_i, # max_age is a required parameter
407
- include_subdomains: true, # whether or not to apply pins to subdomains
408
- # Per the spec, SHA256 hashes are the only currently supported format.
409
- pins: [
410
- {sha256: 'b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c'},
411
- {sha256: '73a2c64f9545172c1195efb6616ca5f7afd1df6f245407cafb90de3998a1c97f'}
412
- ],
413
- report_only: true, # defaults to false (report-only mode)
414
- report_uri: 'https://report-uri.io/example-hpkp'
415
- }
416
- ```
417
-
418
- ### Cookies
419
-
420
- SecureHeaders supports `Secure`, `HttpOnly` and [`SameSite`](https://tools.ietf.org/html/draft-west-first-party-cookies-07) cookies. These can be defined in the form of a boolean, or as a Hash for more refined configuration.
421
-
422
- __Note__: Regardless of the configuration specified, Secure cookies are only enabled for HTTPS requests.
423
-
424
- #### Boolean-based configuration
425
-
426
- Boolean-based configuration is intended to globally enable or disable a specific cookie attribute.
427
-
428
- ```ruby
429
- config.cookies = {
430
- secure: true, # mark all cookies as Secure
431
- httponly: false, # do not mark any cookies as HttpOnly
432
- }
433
- ```
434
-
435
- #### Hash-based configuration
436
-
437
- Hash-based configuration allows for fine-grained control.
438
-
439
- ```ruby
440
- config.cookies = {
441
- secure: { except: ['_guest'] }, # mark all but the `_guest` cookie as Secure
442
- httponly: { only: ['_rails_session'] }, # only mark the `_rails_session` cookie as HttpOnly
443
- }
444
- ```
445
-
446
- #### SameSite cookie configuration
447
-
448
- SameSite cookies permit either `Strict` or `Lax` enforcement mode options.
449
-
450
- ```ruby
451
- config.cookies = {
452
- samesite: {
453
- strict: true # mark all cookies as SameSite=Strict
454
- }
455
- }
456
- ```
457
-
458
- `Strict` and `Lax` enforcement modes can also be specified using a Hash.
459
-
460
- ```ruby
461
- config.cookies = {
462
- samesite: {
463
- strict: { only: ['_rails_session'] },
464
- lax: { only: ['_guest'] }
465
- }
466
- }
467
- ```
468
-
469
- ### Using with Sinatra
470
-
471
- Here's an example using SecureHeaders for Sinatra applications:
472
-
473
- ```ruby
474
- require 'rubygems'
475
- require 'sinatra'
476
- require 'haml'
477
- require 'secure_headers'
478
-
479
- use SecureHeaders::Middleware
480
-
481
- SecureHeaders::Configuration.default do |config|
482
- ...
483
- end
484
-
485
- class Donkey < Sinatra::Application
486
- set :root, APP_ROOT
487
-
488
- get '/' do
489
- SecureHeaders.override_x_frame_options(request, SecureHeaders::OPT_OUT)
490
- haml :index
491
- end
492
- end
493
- ```
494
146
 
495
147
  ## Similar libraries
496
148
 
data/docs/HPKP.md ADDED
@@ -0,0 +1,17 @@
1
+ ## HTTP Public Key Pins
2
+
3
+ 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.
4
+
5
+ ```ruby
6
+ config.hpkp = {
7
+ max_age: 60.days.to_i, # max_age is a required parameter
8
+ include_subdomains: true, # whether or not to apply pins to subdomains
9
+ # Per the spec, SHA256 hashes are the only currently supported format.
10
+ pins: [
11
+ {sha256: 'b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c'},
12
+ {sha256: '73a2c64f9545172c1195efb6616ca5f7afd1df6f245407cafb90de3998a1c97f'}
13
+ ],
14
+ report_only: true, # defaults to false (report-only mode)
15
+ report_uri: 'https://report-uri.io/example-hpkp'
16
+ }
17
+ ```
data/docs/cookies.md ADDED
@@ -0,0 +1,50 @@
1
+ ## Cookies
2
+
3
+ SecureHeaders supports `Secure`, `HttpOnly` and [`SameSite`](https://tools.ietf.org/html/draft-west-first-party-cookies-07) cookies. These can be defined in the form of a boolean, or as a Hash for more refined configuration.
4
+
5
+ __Note__: Regardless of the configuration specified, Secure cookies are only enabled for HTTPS requests.
6
+
7
+ #### Boolean-based configuration
8
+
9
+ Boolean-based configuration is intended to globally enable or disable a specific cookie attribute.
10
+
11
+ ```ruby
12
+ config.cookies = {
13
+ secure: true, # mark all cookies as Secure
14
+ httponly: false, # do not mark any cookies as HttpOnly
15
+ }
16
+ ```
17
+
18
+ #### Hash-based configuration
19
+
20
+ Hash-based configuration allows for fine-grained control.
21
+
22
+ ```ruby
23
+ config.cookies = {
24
+ secure: { except: ['_guest'] }, # mark all but the `_guest` cookie as Secure
25
+ httponly: { only: ['_rails_session'] }, # only mark the `_rails_session` cookie as HttpOnly
26
+ }
27
+ ```
28
+
29
+ #### SameSite cookie configuration
30
+
31
+ SameSite cookies permit either `Strict` or `Lax` enforcement mode options.
32
+
33
+ ```ruby
34
+ config.cookies = {
35
+ samesite: {
36
+ strict: true # mark all cookies as SameSite=Strict
37
+ }
38
+ }
39
+ ```
40
+
41
+ `Strict` and `Lax` enforcement modes can also be specified using a Hash.
42
+
43
+ ```ruby
44
+ config.cookies = {
45
+ samesite: {
46
+ strict: { only: ['_rails_session'] },
47
+ lax: { only: ['_guest'] }
48
+ }
49
+ }
50
+ ```
data/docs/hashes.md ADDED
@@ -0,0 +1,64 @@
1
+ ## Hash
2
+
3
+ `script`/`style-src` hashes can be used to whitelist inline content that is static. This has the benefit of allowing inline content without opening up the possibility of dynamic javascript like you would with a `nonce`.
4
+
5
+ You can add hash sources directly to your policy :
6
+
7
+ ```ruby
8
+ ::SecureHeaders::Configuration.default do |config|
9
+ config.csp = {
10
+ default_src: %w('self')
11
+
12
+ # this is a made up value but browsers will show the expected hash in the console.
13
+ script_src: %w(sha256-123456)
14
+ }
15
+ end
16
+ ```
17
+
18
+ You can also use the automated inline script detection/collection/computation of hash source values in your app.
19
+
20
+ ```bash
21
+ rake secure_headers:generate_hashes
22
+ ```
23
+
24
+ This will generate a file (`config/config/secure_headers_generated_hashes.yml` by default, you can override by setting `ENV["secure_headers_generated_hashes_file"]`) containing a mapping of file names with the array of hash values found on that page. When ActionView renders a given file, we check if there are any known hashes for that given file. If so, they are added as values to the header.
25
+
26
+ ```yaml
27
+ ---
28
+ scripts:
29
+ app/views/asdfs/index.html.erb:
30
+ - "'sha256-yktKiAsZWmc8WpOyhnmhQoDf9G2dAZvuBBC+V0LGQhg='"
31
+ styles:
32
+ app/views/asdfs/index.html.erb:
33
+ - "'sha256-SLp6LO3rrKDJwsG9uJUxZapb4Wp2Zhj6Bu3l+d9rnAY='"
34
+ - "'sha256-HSGHqlRoKmHAGTAJ2Rq0piXX4CnEbOl1ArNd6ejp2TE='"
35
+ ```
36
+
37
+ ##### Helpers
38
+
39
+ **This will not compute dynamic hashes** by design. The output of both helpers will be a plain `script`/`style` tag without modification and the known hashes for a given file will be added to `script-src`/`style-src` when `hashed_javascript_tag` and `hashed_style_tag` are used. You can use `raise_error_on_unrecognized_hash = true` to be extra paranoid that you have precomputed hash values for all of your inline content. By default, this will raise an error in non-production environments.
40
+
41
+ ```erb
42
+ <%= hashed_style_tag do %>
43
+ body {
44
+ background-color: black;
45
+ }
46
+ <% end %>
47
+
48
+ <%= hashed_style_tag do %>
49
+ body {
50
+ font-size: 30px;
51
+ font-color: green;
52
+ }
53
+ <% end %>
54
+
55
+ <%= hashed_javascript_tag do %>
56
+ console.log(1)
57
+ <% end %>
58
+ ```
59
+
60
+ ```
61
+ Content-Security-Policy: ...
62
+ script-src 'sha256-yktKiAsZWmc8WpOyhnmhQoDf9G2dAZvuBBC+V0LGQhg=' ... ;
63
+ style-src 'sha256-SLp6LO3rrKDJwsG9uJUxZapb4Wp2Zhj6Bu3l+d9rnAY=' 'sha256-HSGHqlRoKmHAGTAJ2Rq0piXX4CnEbOl1ArNd6ejp2TE=' ...;
64
+ ```
@@ -0,0 +1,107 @@
1
+ ## Named Appends
2
+
3
+ Named Appends are blocks of code that can be reused and composed during requests. e.g. If a certain partial is rendered conditionally, and the csp needs to be adjusted for that partial, you can create a named append for that situation. The value returned by the block will be passed into `append_content_security_policy_directives`. The current request object is passed as an argument to the block for even more flexibility.
4
+
5
+ ```ruby
6
+ def show
7
+ if include_widget?
8
+ @widget = widget.render
9
+ use_content_security_policy_named_append(:widget_partial)
10
+ end
11
+ end
12
+
13
+
14
+ SecureHeaders::Configuration.named_append(:widget_partial) do |request|
15
+ SecureHeaders.override_x_frame_options(request, "DENY")
16
+ if request.controller_instance.current_user.in_test_bucket?
17
+ { child_src: %w(beta.thirdpartyhost.com) }
18
+ else
19
+ { child_src: %w(thirdpartyhost.com) }
20
+ end
21
+ end
22
+ ```
23
+
24
+ You can use as many named appends as you would like per request, but be careful because order of inclusion matters. Consider the following:
25
+
26
+ ```ruby
27
+ SecureHeader::Configuration.default do |config|
28
+ config.csp = { default_src: %w('self')}
29
+ end
30
+
31
+ SecureHeaders::Configuration.named_append(:A) do |request|
32
+ { default_src: %w(myhost.com) }
33
+ end
34
+
35
+ SecureHeaders::Configuration.named_append(:B) do |request|
36
+ { script_src: %w('unsafe-eval') }
37
+ end
38
+ ```
39
+
40
+ The following code will produce different policies due to the way policies are normalized (e.g. providing a previously undefined directive that inherits from `default-src`, removing host source values when `*` is provided. Removing `'none'` when additional values are present, etc.):
41
+
42
+ ```ruby
43
+ def index
44
+ use_content_security_policy_named_append(:A)
45
+ use_content_security_policy_named_append(:B)
46
+ # produces default-src 'self' myhost.com; script-src 'self' myhost.com 'unsafe-eval';
47
+ end
48
+
49
+ def show
50
+ use_content_security_policy_named_append(:B)
51
+ use_content_security_policy_named_append(:A)
52
+ # produces default-src 'self' myhost.com; script-src 'self' 'unsafe-eval';
53
+ end
54
+ ```
55
+
56
+
57
+ ## Named overrides
58
+
59
+ Named overrides serve two purposes:
60
+
61
+ * To be able to refer to a configuration by simple name.
62
+ * By precomputing the headers for a named configuration, the headers generated once and reused over every request.
63
+
64
+ To use a named override, drop a `SecureHeaders::Configuration.override` block **outside** of method definitions and then declare which named override you'd like to use. You can even override an override.
65
+
66
+ ```ruby
67
+ class ApplicationController < ActionController::Base
68
+ SecureHeaders::Configuration.default do |config|
69
+ config.csp = {
70
+ default_src: %w('self'),
71
+ script_src: %w(example.org)
72
+ }
73
+ end
74
+
75
+ # override default configuration
76
+ SecureHeaders::Configuration.override(:script_from_otherdomain_com) do |config|
77
+ config.csp[:script_src] << "otherdomain.com"
78
+ end
79
+
80
+ # overrides the :script_from_otherdomain_com configuration
81
+ SecureHeaders::Configuration.override(:another_config, :script_from_otherdomain_com) do |config|
82
+ config.csp[:script_src] << "evenanotherdomain.com"
83
+ end
84
+ end
85
+
86
+ class MyController < ApplicationController
87
+ def index
88
+ # Produces default-src 'self'; script-src example.org otherdomain.com
89
+ use_secure_headers_override(:script_from_otherdomain_com)
90
+ end
91
+
92
+ def show
93
+ # Produces default-src 'self'; script-src example.org otherdomain.org evenanotherdomain.com
94
+ use_secure_headers_override(:another_config)
95
+ end
96
+ end
97
+ ```
98
+
99
+ By default, a no-op configuration is provided. No headers will be set when this default override is used.
100
+
101
+ ```ruby
102
+ class MyController < ApplicationController
103
+ def index
104
+ SecureHeaders.opt_out_of_all_protection(request)
105
+ end
106
+ end
107
+ ```
@@ -0,0 +1,105 @@
1
+ ## Per-action configuration
2
+
3
+ You can override the settings for a given action by producing a temporary override. Be aware that because of the dynamic nature of the value, the header values will be computed per request.
4
+
5
+ ```ruby
6
+ # Given a config of:
7
+ ::SecureHeaders::Configuration.default do |config|
8
+ config.csp = {
9
+ default_src: %w('self'),
10
+ script_src: %w('self')
11
+ }
12
+ end
13
+
14
+ class MyController < ApplicationController
15
+ def index
16
+ # Append value to the source list, override 'none' values
17
+ # Produces: default-src 'self'; script-src 'self' s3.amazonaws.com; object-src 'self' www.youtube.com
18
+ append_content_security_policy_directives(script_src: %w(s3.amazonaws.com), object_src: %w('self' www.youtube.com))
19
+
20
+ # Overrides the previously set source list, override 'none' values
21
+ # Produces: default-src 'self'; script-src s3.amazonaws.com; object-src 'self'
22
+ override_content_security_policy_directives(script_src: %w(s3.amazonaws.com), object_src: %w('self'))
23
+
24
+ # Global settings default to "sameorigin"
25
+ override_x_frame_options("DENY")
26
+ end
27
+ ```
28
+
29
+ The following methods are available as controller instance methods. They are also available as class methods, but require you to pass in the `request` object.
30
+ * `append_content_security_policy_directives(hash)`: appends each value to the corresponding CSP app-wide configuration.
31
+ * `override_content_security_policy_directives(hash)`: merges the hash into the app-wide configuration, overwriting any previous config
32
+ * `override_x_frame_options(value)`: sets the `X-Frame-Options header` to `value`
33
+
34
+ ## Appending / overriding Content Security Policy
35
+
36
+ When manipulating content security policy, there are a few things to consider. The default header value is `default-src https:` which corresponds to a default configuration of `{ default_src: %w(https:)}`.
37
+
38
+ #### Append to the policy with a directive other than `default_src`
39
+
40
+ The value of `default_src` is joined with the addition if the it is a [fetch directive](https://w3c.github.io/webappsec-csp/#directives-fetch). Note the `https:` is carried over from the `default-src` config. If you do not want this, use `override_content_security_policy_directives` instead. To illustrate:
41
+
42
+ ```ruby
43
+ ::SecureHeaders::Configuration.default do |config|
44
+ config.csp = {
45
+ default_src: %w('self')
46
+ }
47
+ end
48
+ ```
49
+
50
+ Code | Result
51
+ ------------- | -------------
52
+ `append_content_security_policy_directives(script_src: %w(mycdn.com))` | `default-src 'self'; script-src 'self' mycdn.com`
53
+ `override_content_security_policy_directives(script_src: %w(mycdn.com))` | `default-src 'self'; script-src mycdn.com`
54
+
55
+ #### Nonce
56
+
57
+ You can use a view helper to automatically add nonces to script tags:
58
+
59
+ ```erb
60
+ <%= nonced_javascript_tag do %>
61
+ console.log("nonced!");
62
+ <% end %>
63
+
64
+ <%= nonced_style_tag do %>
65
+ body {
66
+ background-color: black;
67
+ }
68
+ <% end %>
69
+ ```
70
+
71
+ becomes:
72
+
73
+ ```html
74
+ <script nonce="/jRAxuLJsDXAxqhNBB7gg7h55KETtDQBXe4ZL+xIXwI=">
75
+ console.log("nonced!")
76
+ </script>
77
+ <style nonce="/jRAxuLJsDXAxqhNBB7gg7h55KETtDQBXe4ZL+xIXwI=">
78
+ body {
79
+ background-color: black;
80
+ }
81
+ </style>
82
+ ```
83
+
84
+ ```
85
+
86
+ Content-Security-Policy: ...
87
+ script-src 'nonce-/jRAxuLJsDXAxqhNBB7gg7h55KETtDQBXe4ZL+xIXwI=' ...;
88
+ style-src 'nonce-/jRAxuLJsDXAxqhNBB7gg7h55KETtDQBXe4ZL+xIXwI=' ...;
89
+ ```
90
+
91
+ `script`/`style-nonce` can be used to whitelist inline content. To do this, call the `content_security_policy_script_nonce` or `content_security_policy_style_nonce` then set the nonce attributes on the various tags.
92
+
93
+ ```erb
94
+ <script nonce="<%= content_security_policy_script_nonce %>">
95
+ console.log("whitelisted, will execute")
96
+ </script>
97
+
98
+ <script nonce="lol">
99
+ console.log("won't execute, not whitelisted")
100
+ </script>
101
+
102
+ <script>
103
+ console.log("won't execute, not whitelisted")
104
+ </script>
105
+ ```
data/docs/sinatra.md ADDED
@@ -0,0 +1,25 @@
1
+ ## Sinatra
2
+
3
+ Here's an example using SecureHeaders for Sinatra applications:
4
+
5
+ ```ruby
6
+ require 'rubygems'
7
+ require 'sinatra'
8
+ require 'haml'
9
+ require 'secure_headers'
10
+
11
+ use SecureHeaders::Middleware
12
+
13
+ SecureHeaders::Configuration.default do |config|
14
+ ...
15
+ end
16
+
17
+ class Donkey < Sinatra::Application
18
+ set :root, APP_ROOT
19
+
20
+ get '/' do
21
+ SecureHeaders.override_x_frame_options(request, SecureHeaders::OPT_OUT)
22
+ haml :index
23
+ end
24
+ end
25
+ ```
@@ -116,7 +116,7 @@ module SecureHeaders
116
116
 
117
117
  attr_writer :hsts, :x_frame_options, :x_content_type_options,
118
118
  :x_xss_protection, :x_download_options, :x_permitted_cross_domain_policies,
119
- :referrer_policy
119
+ :referrer_policy, :clear_site_data
120
120
 
121
121
  attr_reader :cached_headers, :csp, :cookies, :csp_report_only, :hpkp, :hpkp_report_host
122
122
 
@@ -150,6 +150,7 @@ module SecureHeaders
150
150
  copy.x_xss_protection = @x_xss_protection
151
151
  copy.x_download_options = @x_download_options
152
152
  copy.x_permitted_cross_domain_policies = @x_permitted_cross_domain_policies
153
+ copy.clear_site_data = @clear_site_data
153
154
  copy.referrer_policy = @referrer_policy
154
155
  copy.hpkp = @hpkp
155
156
  copy.hpkp_report_host = @hpkp_report_host
@@ -181,6 +182,7 @@ module SecureHeaders
181
182
  XXssProtection.validate_config!(@x_xss_protection)
182
183
  XDownloadOptions.validate_config!(@x_download_options)
183
184
  XPermittedCrossDomainPolicies.validate_config!(@x_permitted_cross_domain_policies)
185
+ ClearSiteData.validate_config!(@clear_site_data)
184
186
  PublicKeyPins.validate_config!(@hpkp)
185
187
  Cookie.validate_config!(@cookies)
186
188
  end
@@ -0,0 +1,51 @@
1
+ module SecureHeaders
2
+ class ClearSiteDataConfigError < StandardError; end
3
+ class ClearSiteData
4
+ HEADER_NAME = "Clear-Site-Data".freeze
5
+ TYPES = "types".freeze
6
+
7
+ # Valid `types`
8
+ CACHE = "cache".freeze
9
+ COOKIES = "cookies".freeze
10
+ STORAGE = "storage".freeze
11
+ EXECTION_CONTEXTS = "executionContexts".freeze
12
+ ALL_TYPES = [CACHE, COOKIES, STORAGE, EXECTION_CONTEXTS]
13
+
14
+ CONFIG_KEY = :clear_site_data
15
+
16
+ class << self
17
+ # Public: make an Clear-Site-Data header name, value pair
18
+ #
19
+ # Returns nil if not configured, returns header name and value if configured.
20
+ def make_header(config=nil)
21
+ case config
22
+ when nil, OPT_OUT, []
23
+ # noop
24
+ when Array
25
+ [HEADER_NAME, JSON.dump(TYPES => config)]
26
+ when true
27
+ [HEADER_NAME, JSON.dump(TYPES => ALL_TYPES)]
28
+ end
29
+ end
30
+
31
+ def validate_config!(config)
32
+ case config
33
+ when nil, OPT_OUT, true
34
+ # valid
35
+ when Array
36
+ unless config.all? { |t| t.is_a?(String) }
37
+ raise ClearSiteDataConfigError.new("types must be Strings")
38
+ end
39
+
40
+ begin
41
+ JSON.dump(config)
42
+ rescue JSON::GeneratorError, Encoding::UndefinedConversionError
43
+ raise ClearSiteDataConfigError.new("types must serializable by JSON")
44
+ end
45
+ else
46
+ raise ClearSiteDataConfigError.new("config must be an Array of Strings or `true`")
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -9,6 +9,7 @@ module SecureHeaders
9
9
  # constants to be used for version-specific UA sniffing
10
10
  VERSION_46 = ::UserAgent::Version.new("46")
11
11
  VERSION_10 = ::UserAgent::Version.new("10")
12
+ FALLBACK_VERSION = ::UserAgent::Version.new("0")
12
13
 
13
14
  def initialize(config = nil, user_agent = OTHER)
14
15
  @config = if config.is_a?(Hash)
@@ -213,7 +214,7 @@ module SecureHeaders
213
214
  # Returns an array of symbols representing the directives.
214
215
  def supported_directives
215
216
  @supported_directives ||= if VARIATIONS[@parsed_ua.browser]
216
- if @parsed_ua.browser == "Firefox" && @parsed_ua.version >= VERSION_46
217
+ if @parsed_ua.browser == "Firefox" && ((@parsed_ua.version || FALLBACK_VERSION) >= VERSION_46)
217
218
  VARIATIONS["FirefoxTransitional"]
218
219
  else
219
220
  VARIATIONS[@parsed_ua.browser]
@@ -14,6 +14,7 @@ module SecureHeaders
14
14
  STAR = "*".freeze
15
15
  UNSAFE_INLINE = "'unsafe-inline'".freeze
16
16
  UNSAFE_EVAL = "'unsafe-eval'".freeze
17
+ STRICT_DYNAMIC = "'strict-dynamic'".freeze
17
18
 
18
19
  # leftover deprecated values that will be in common use upon upgrading.
19
20
  DEPRECATED_SOURCE_VALUES = [SELF, NONE, UNSAFE_EVAL, UNSAFE_INLINE, "inline", "eval"].map { |value| value.delete("'") }.freeze
@@ -217,7 +218,7 @@ module SecureHeaders
217
218
  def nonces_supported?(user_agent)
218
219
  user_agent = UserAgent.parse(user_agent) if user_agent.is_a?(String)
219
220
  MODERN_BROWSERS.include?(user_agent.browser) ||
220
- user_agent.browser == "Safari" && user_agent.version >= CSP::VERSION_10
221
+ user_agent.browser == "Safari" && (user_agent.version || CSP::FALLBACK_VERSION) >= CSP::VERSION_10
221
222
  end
222
223
 
223
224
  # Public: combine the values from two different configs.
@@ -6,6 +6,9 @@ module SecureHeaders
6
6
  VALID_POLICIES = %w(
7
7
  no-referrer
8
8
  no-referrer-when-downgrade
9
+ same-origin
10
+ strict-origin
11
+ strict-origin-when-cross-origin
9
12
  origin
10
13
  origin-when-cross-origin
11
14
  unsafe-url
@@ -10,6 +10,7 @@ require "secure_headers/headers/x_content_type_options"
10
10
  require "secure_headers/headers/x_download_options"
11
11
  require "secure_headers/headers/x_permitted_cross_domain_policies"
12
12
  require "secure_headers/headers/referrer_policy"
13
+ require "secure_headers/headers/clear_site_data"
13
14
  require "secure_headers/middleware"
14
15
  require "secure_headers/railtie"
15
16
  require "secure_headers/view_helper"
@@ -50,6 +51,7 @@ module SecureHeaders
50
51
  CSP = ContentSecurityPolicy
51
52
 
52
53
  ALL_HEADER_CLASSES = [
54
+ ClearSiteData,
53
55
  ContentSecurityPolicyConfig,
54
56
  ContentSecurityPolicyReportOnlyConfig,
55
57
  StrictTransportSecurity,
@@ -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.5.0"
4
+ gem.version = "3.6.0"
5
5
  gem.authors = ["Neil Matatall"]
6
6
  gem.email = ["neil.matatall@gmail.com"]
7
7
  gem.description = 'Security related headers all in one gem.'
@@ -0,0 +1,103 @@
1
+ require 'spec_helper'
2
+
3
+ module SecureHeaders
4
+ describe ClearSiteData do
5
+ describe "make_header" do
6
+ it "returns nil with nil config" do
7
+ expect(described_class.make_header).to be_nil
8
+ end
9
+
10
+ it "returns nil with empty config" do
11
+ expect(described_class.make_header([])).to be_nil
12
+ end
13
+
14
+ it "returns nil with opt-out config" do
15
+ expect(described_class.make_header(OPT_OUT)).to be_nil
16
+ end
17
+
18
+ it "returns all types with `true` config" do
19
+ name, value = described_class.make_header(true)
20
+
21
+ expect(name).to eq(ClearSiteData::HEADER_NAME)
22
+ expect(value).to eq(normalize_json(<<-HERE))
23
+ {
24
+ "types": [
25
+ "cache",
26
+ "cookies",
27
+ "storage",
28
+ "executionContexts"
29
+ ]
30
+ }
31
+ HERE
32
+ end
33
+
34
+ it "returns specified types" do
35
+ name, value = described_class.make_header(["foo", "bar"])
36
+
37
+ expect(name).to eq(ClearSiteData::HEADER_NAME)
38
+ expect(value).to eq(normalize_json(<<-HERE))
39
+ {
40
+ "types": [
41
+ "foo",
42
+ "bar"
43
+ ]
44
+ }
45
+ HERE
46
+ end
47
+ end
48
+
49
+ describe "validate_config!" do
50
+ it "succeeds for `true` config" do
51
+ expect do
52
+ described_class.validate_config!(true)
53
+ end.not_to raise_error
54
+ end
55
+
56
+ it "succeeds for `nil` config" do
57
+ expect do
58
+ described_class.validate_config!(nil)
59
+ end.not_to raise_error
60
+ end
61
+
62
+ it "succeeds for opt-out config" do
63
+ expect do
64
+ described_class.validate_config!(OPT_OUT)
65
+ end.not_to raise_error
66
+ end
67
+
68
+ it "succeeds for empty config" do
69
+ expect do
70
+ described_class.validate_config!([])
71
+ end.not_to raise_error
72
+ end
73
+
74
+ it "succeeds for Array of Strings config" do
75
+ expect do
76
+ described_class.validate_config!(["foo"])
77
+ end.not_to raise_error
78
+ end
79
+
80
+ it "fails for Array of non-String config" do
81
+ expect do
82
+ described_class.validate_config!([1])
83
+ end.to raise_error(ClearSiteDataConfigError)
84
+ end
85
+
86
+ it "fails for non-serializable config" do
87
+ expect do
88
+ described_class.validate_config!(["hi \255"])
89
+ end.to raise_error(ClearSiteDataConfigError)
90
+ end
91
+
92
+ it "fails for other types of config" do
93
+ expect do
94
+ described_class.validate_config!(:cookies)
95
+ end.to raise_error(ClearSiteDataConfigError)
96
+ end
97
+ end
98
+
99
+ def normalize_json(json)
100
+ JSON.dump(JSON.parse(json))
101
+ end
102
+ end
103
+ end
@@ -107,6 +107,11 @@ module SecureHeaders
107
107
  expect(firefox_transitional).not_to match(/frame-src/)
108
108
  end
109
109
 
110
+ it "supports strict-dynamic" do
111
+ csp = ContentSecurityPolicy.new({default_src: %w('self'), script_src: [ContentSecurityPolicy::STRICT_DYNAMIC], script_nonce: 123456}, USER_AGENTS[:chrome])
112
+ expect(csp.value).to eq("default-src 'self'; script-src 'strict-dynamic' 'nonce-123456'")
113
+ end
114
+
110
115
  context "browser sniffing" do
111
116
  let (:complex_opts) do
112
117
  (ContentSecurityPolicy::ALL_DIRECTIVES - [:frame_src]).each_with_object({}) do |directive, hash|
@@ -149,6 +154,13 @@ module SecureHeaders
149
154
  policy = ContentSecurityPolicy.new(complex_opts, USER_AGENTS[:safari6])
150
155
  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")
151
156
  end
157
+
158
+ it "falls back to standard Firefox defaults when the useragent version is not present" do
159
+ ua = USER_AGENTS[:firefox].dup
160
+ allow(ua).to receive(:version).and_return(nil)
161
+ policy = ContentSecurityPolicy.new(complex_opts, ua)
162
+ 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; 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")
163
+ end
152
164
  end
153
165
  end
154
166
  end
@@ -18,6 +18,24 @@ module SecureHeaders
18
18
  end.not_to raise_error
19
19
  end
20
20
 
21
+ it "accepts 'same-origin'" do
22
+ expect do
23
+ ReferrerPolicy.validate_config!("same-origin")
24
+ end.not_to raise_error
25
+ end
26
+
27
+ it "accepts 'strict-origin'" do
28
+ expect do
29
+ ReferrerPolicy.validate_config!("strict-origin")
30
+ end.not_to raise_error
31
+ end
32
+
33
+ it "accepts 'strict-origin-when-cross-origin'" do
34
+ expect do
35
+ ReferrerPolicy.validate_config!("strict-origin-when-cross-origin")
36
+ end.not_to raise_error
37
+ end
38
+
21
39
  it "accepts 'origin'" do
22
40
  expect do
23
41
  ReferrerPolicy.validate_config!("origin")
@@ -530,6 +530,14 @@ module SecureHeaders
530
530
  end.to raise_error(XContentTypeOptionsConfigError)
531
531
  end
532
532
 
533
+ it "validates your clear site data config upon configuration" do
534
+ expect do
535
+ Configuration.default do |config|
536
+ config.clear_site_data = 1
537
+ end
538
+ end.to raise_error(ClearSiteDataConfigError)
539
+ end
540
+
533
541
  it "validates your x_xss config upon configuration" do
534
542
  expect do
535
543
  Configuration.default do |config|
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.5.0
4
+ version: 3.6.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: 2016-10-12 00:00:00.000000000 Z
11
+ date: 2017-01-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -58,9 +58,16 @@ files:
58
58
  - LICENSE
59
59
  - README.md
60
60
  - Rakefile
61
+ - docs/HPKP.md
62
+ - docs/cookies.md
63
+ - docs/hashes.md
64
+ - docs/named_overrides_and_appends.md
65
+ - docs/per_action_configuration.md
66
+ - docs/sinatra.md
61
67
  - lib/secure_headers.rb
62
68
  - lib/secure_headers/configuration.rb
63
69
  - lib/secure_headers/hash_helper.rb
70
+ - lib/secure_headers/headers/clear_site_data.rb
64
71
  - lib/secure_headers/headers/content_security_policy.rb
65
72
  - lib/secure_headers/headers/content_security_policy_config.rb
66
73
  - lib/secure_headers/headers/cookie.rb
@@ -80,6 +87,7 @@ files:
80
87
  - lib/tasks/tasks.rake
81
88
  - secure_headers.gemspec
82
89
  - spec/lib/secure_headers/configuration_spec.rb
90
+ - spec/lib/secure_headers/headers/clear_site_data_spec.rb
83
91
  - spec/lib/secure_headers/headers/content_security_policy_spec.rb
84
92
  - spec/lib/secure_headers/headers/cookie_spec.rb
85
93
  - spec/lib/secure_headers/headers/policy_management_spec.rb
@@ -123,6 +131,7 @@ summary: Add easily configured security headers to responses including content-s
123
131
  x-frame-options, strict-transport-security, etc.
124
132
  test_files:
125
133
  - spec/lib/secure_headers/configuration_spec.rb
134
+ - spec/lib/secure_headers/headers/clear_site_data_spec.rb
126
135
  - spec/lib/secure_headers/headers/content_security_policy_spec.rb
127
136
  - spec/lib/secure_headers/headers/cookie_spec.rb
128
137
  - spec/lib/secure_headers/headers/policy_management_spec.rb