secure_headers 3.5.0.pre → 3.6.2

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.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/.travis.yml +2 -0
  4. data/CHANGELOG.md +20 -1
  5. data/Gemfile +1 -0
  6. data/LICENSE +4 -199
  7. data/README.md +37 -388
  8. data/docs/HPKP.md +17 -0
  9. data/docs/cookies.md +50 -0
  10. data/docs/hashes.md +64 -0
  11. data/docs/named_overrides_and_appends.md +107 -0
  12. data/docs/per_action_configuration.md +105 -0
  13. data/docs/sinatra.md +25 -0
  14. data/lib/secure_headers/configuration.rb +5 -3
  15. data/lib/secure_headers/headers/clear_site_data.rb +51 -0
  16. data/lib/secure_headers/headers/content_security_policy.rb +6 -2
  17. data/lib/secure_headers/headers/content_security_policy_config.rb +21 -12
  18. data/lib/secure_headers/headers/policy_management.rb +14 -2
  19. data/lib/secure_headers/headers/referrer_policy.rb +4 -1
  20. data/lib/secure_headers/headers/strict_transport_security.rb +1 -1
  21. data/lib/secure_headers/headers/x_content_type_options.rb +1 -1
  22. data/lib/secure_headers/headers/x_download_options.rb +1 -1
  23. data/lib/secure_headers/headers/x_frame_options.rb +1 -1
  24. data/lib/secure_headers/headers/x_permitted_cross_domain_policies.rb +1 -1
  25. data/lib/secure_headers/headers/x_xss_protection.rb +1 -1
  26. data/lib/secure_headers/view_helper.rb +8 -0
  27. data/lib/secure_headers.rb +4 -1
  28. data/secure_headers.gemspec +1 -1
  29. data/spec/lib/secure_headers/headers/clear_site_data_spec.rb +103 -0
  30. data/spec/lib/secure_headers/headers/content_security_policy_spec.rb +17 -0
  31. data/spec/lib/secure_headers/headers/referrer_policy_spec.rb +18 -0
  32. data/spec/lib/secure_headers/middleware_spec.rb +12 -0
  33. data/spec/lib/secure_headers/view_helpers_spec.rb +10 -0
  34. data/spec/lib/secure_headers_spec.rb +22 -0
  35. data/spec/spec_helper.rb +2 -1
  36. metadata +14 -5
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,14 +18,34 @@ 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
 
23
- ## Use
27
+ ## Documentation
24
28
 
25
- `gem install secure_headers`
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
+ ```
26
49
 
27
50
  ## Configuration
28
51
 
@@ -39,16 +62,23 @@ SecureHeaders::Configuration.default do |config|
39
62
  lax: true # mark all cookies as SameSite=lax
40
63
  }
41
64
  }
42
- config.hsts = "max-age=#{20.years.to_i}; includeSubdomains; preload"
65
+ # Add "; preload" and submit the site to hstspreload.org for best protection.
66
+ config.hsts = "max-age=#{20.years.to_i}; includeSubdomains"
43
67
  config.x_frame_options = "DENY"
44
68
  config.x_content_type_options = "nosniff"
45
69
  config.x_xss_protection = "1; mode=block"
46
70
  config.x_download_options = "noopen"
47
71
  config.x_permitted_cross_domain_policies = "none"
48
72
  config.referrer_policy = "origin-when-cross-origin"
73
+ config.clear_site_data = [
74
+ "cache",
75
+ "cookies",
76
+ "storage",
77
+ "executionContexts"
78
+ ]
49
79
  config.csp = {
50
80
  # "meta" values. these will shaped the header, but the values are not included in the header.
51
- report_only: true, # default: false [DEPRECATED: instead, configure csp_report_only]
81
+ # report_only: true, # default: false [DEPRECATED from 3.5.0: instead, configure csp_report_only]
52
82
  preserve_schemes: true, # default: false. Schemes are removed from host sources to save bytes and discourage mixed content.
53
83
 
54
84
  # directive values: these values will directly translate into source directives
@@ -69,6 +99,7 @@ SecureHeaders::Configuration.default do |config|
69
99
  upgrade_insecure_requests: true, # see https://www.w3.org/TR/upgrade-insecure-requests/
70
100
  report_uri: %w(https://report-uri.io/example-csp)
71
101
  }
102
+ # This is available only from 3.5.0; use the `report_only: true` setting for 3.4.1 and below.
72
103
  config.csp_report_only = config.csp.merge({
73
104
  img_src: %w(somewhereelse.com),
74
105
  report_uri: %w(https://report-uri.io/example-csp-report-only)
@@ -86,17 +117,9 @@ SecureHeaders::Configuration.default do |config|
86
117
  end
87
118
  ```
88
119
 
89
- ### rails 2
90
-
91
- 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.
92
-
93
- ```ruby
94
- use SecureHeaders::Middleware
95
- ```
96
-
97
120
  ## Default values
98
121
 
99
- 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:
122
+ All headers except for PublicKeyPins and ClearSiteData have a default value. The default set of headers is:
100
123
 
101
124
  ```
102
125
  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'
@@ -121,381 +144,6 @@ Configuration.default do |config|
121
144
  end
122
145
  ```
123
146
 
124
- If **
125
-
126
- ## Named Appends
127
-
128
- 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.
129
-
130
- ```ruby
131
- def show
132
- if include_widget?
133
- @widget = widget.render
134
- use_content_security_policy_named_append(:widget_partial)
135
- end
136
- end
137
-
138
-
139
- SecureHeaders::Configuration.named_append(:widget_partial) do |request|
140
- SecureHeaders.override_x_frame_options(request, "DENY")
141
- if request.controller_instance.current_user.in_test_bucket?
142
- { child_src: %w(beta.thirdpartyhost.com) }
143
- else
144
- { child_src: %w(thirdpartyhost.com) }
145
- end
146
- end
147
- ```
148
-
149
- You can use as many named appends as you would like per request, but be careful because order of inclusion matters. Consider the following:
150
-
151
- ```ruby
152
- SecureHeader::Configuration.default do |config|
153
- config.csp = { default_src: %w('self')}
154
- end
155
-
156
- SecureHeaders::Configuration.named_append(:A) do |request|
157
- { default_src: %w(myhost.com) }
158
- end
159
-
160
- SecureHeaders::Configuration.named_append(:B) do |request|
161
- { script_src: %w('unsafe-eval') }
162
- end
163
- ```
164
-
165
- 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.):
166
-
167
- ```ruby
168
- def index
169
- use_content_security_policy_named_append(:A)
170
- use_content_security_policy_named_append(:B)
171
- # produces default-src 'self' myhost.com; script-src 'self' myhost.com 'unsafe-eval';
172
- end
173
-
174
- def show
175
- use_content_security_policy_named_append(:B)
176
- use_content_security_policy_named_append(:A)
177
- # produces default-src 'self' myhost.com; script-src 'self' 'unsafe-eval';
178
- end
179
- ```
180
-
181
-
182
- ## Named overrides
183
-
184
- Named overrides serve two purposes:
185
-
186
- * To be able to refer to a configuration by simple name.
187
- * By precomputing the headers for a named configuration, the headers generated once and reused over every request.
188
-
189
- 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.
190
-
191
- ```ruby
192
- class ApplicationController < ActionController::Base
193
- SecureHeaders::Configuration.default do |config|
194
- config.csp = {
195
- default_src: %w('self'),
196
- script_src: %w(example.org)
197
- }
198
- end
199
-
200
- # override default configuration
201
- SecureHeaders::Configuration.override(:script_from_otherdomain_com) do |config|
202
- config.csp[:script_src] << "otherdomain.com"
203
- end
204
-
205
- # overrides the :script_from_otherdomain_com configuration
206
- SecureHeaders::Configuration.override(:another_config, :script_from_otherdomain_com) do |config|
207
- config.csp[:script_src] << "evenanotherdomain.com"
208
- end
209
- end
210
-
211
- class MyController < ApplicationController
212
- def index
213
- # Produces default-src 'self'; script-src example.org otherdomain.com
214
- use_secure_headers_override(:script_from_otherdomain_com)
215
- end
216
-
217
- def show
218
- # Produces default-src 'self'; script-src example.org otherdomain.org evenanotherdomain.com
219
- use_secure_headers_override(:another_config)
220
- end
221
- end
222
- ```
223
-
224
- By default, a no-op configuration is provided. No headers will be set when this default override is used.
225
-
226
- ```ruby
227
- class MyController < ApplicationController
228
- def index
229
- SecureHeaders.opt_out_of_all_protection(request)
230
- end
231
- end
232
- ```
233
-
234
- ## Per-action configuration
235
-
236
- 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.
237
-
238
- ```ruby
239
- # Given a config of:
240
- ::SecureHeaders::Configuration.default do |config|
241
- config.csp = {
242
- default_src: %w('self'),
243
- script_src: %w('self')
244
- }
245
- end
246
-
247
- class MyController < ApplicationController
248
- def index
249
- # Append value to the source list, override 'none' values
250
- # Produces: default-src 'self'; script-src 'self' s3.amazonaws.com; object-src 'self' www.youtube.com
251
- append_content_security_policy_directives(script_src: %w(s3.amazonaws.com), object_src: %w('self' www.youtube.com))
252
-
253
- # Overrides the previously set source list, override 'none' values
254
- # Produces: default-src 'self'; script-src s3.amazonaws.com; object-src 'self'
255
- override_content_security_policy_directives(script_src: %w(s3.amazonaws.com), object_src: %w('self'))
256
-
257
- # Global settings default to "sameorigin"
258
- override_x_frame_options("DENY")
259
- end
260
- ```
261
-
262
- 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.
263
- * `append_content_security_policy_directives(hash)`: appends each value to the corresponding CSP app-wide configuration.
264
- * `override_content_security_policy_directives(hash)`: merges the hash into the app-wide configuration, overwriting any previous config
265
- * `override_x_frame_options(value)`: sets the `X-Frame-Options header` to `value`
266
-
267
- ## Appending / overriding Content Security Policy
268
-
269
- 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:)}`.
270
-
271
- #### Append to the policy with a directive other than `default_src`
272
-
273
- 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:
274
-
275
- ```ruby
276
- ::SecureHeaders::Configuration.default do |config|
277
- config.csp = {
278
- default_src: %w('self')
279
- }
280
- end
281
- ```
282
-
283
- Code | Result
284
- ------------- | -------------
285
- `append_content_security_policy_directives(script_src: %w(mycdn.com))` | `default-src 'self'; script-src 'self' mycdn.com`
286
- `override_content_security_policy_directives(script_src: %w(mycdn.com))` | `default-src 'self'; script-src mycdn.com`
287
-
288
- #### Nonce
289
-
290
- You can use a view helper to automatically add nonces to script tags:
291
-
292
- ```erb
293
- <%= nonced_javascript_tag do %>
294
- console.log("nonced!");
295
- <% end %>
296
-
297
- <%= nonced_style_tag do %>
298
- body {
299
- background-color: black;
300
- }
301
- <% end %>
302
- ```
303
-
304
- becomes:
305
-
306
- ```html
307
- <script nonce="/jRAxuLJsDXAxqhNBB7gg7h55KETtDQBXe4ZL+xIXwI=">
308
- console.log("nonced!")
309
- </script>
310
- <style nonce="/jRAxuLJsDXAxqhNBB7gg7h55KETtDQBXe4ZL+xIXwI=">
311
- body {
312
- background-color: black;
313
- }
314
- </style>
315
- ```
316
-
317
- ```
318
-
319
- Content-Security-Policy: ...
320
- script-src 'nonce-/jRAxuLJsDXAxqhNBB7gg7h55KETtDQBXe4ZL+xIXwI=' ...;
321
- style-src 'nonce-/jRAxuLJsDXAxqhNBB7gg7h55KETtDQBXe4ZL+xIXwI=' ...;
322
- ```
323
-
324
- `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.
325
-
326
- ```erb
327
- <script nonce="<%= content_security_policy_script_nonce %>">
328
- console.log("whitelisted, will execute")
329
- </script>
330
-
331
- <script nonce="lol">
332
- console.log("won't execute, not whitelisted")
333
- </script>
334
-
335
- <script>
336
- console.log("won't execute, not whitelisted")
337
- </script>
338
- ```
339
-
340
- #### Hash
341
-
342
- `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`.
343
-
344
- You can add hash sources directly to your policy :
345
-
346
- ```ruby
347
- ::SecureHeaders::Configuration.default do |config|
348
- config.csp = {
349
- default_src: %w('self')
350
-
351
- # this is a made up value but browsers will show the expected hash in the console.
352
- script_src: %w(sha256-123456)
353
- }
354
- end
355
- ```
356
-
357
- You can also use the automated inline script detection/collection/computation of hash source values in your app.
358
-
359
- ```bash
360
- rake secure_headers:generate_hashes
361
- ```
362
-
363
- 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.
364
-
365
- ```yaml
366
- ---
367
- scripts:
368
- app/views/asdfs/index.html.erb:
369
- - "'sha256-yktKiAsZWmc8WpOyhnmhQoDf9G2dAZvuBBC+V0LGQhg='"
370
- styles:
371
- app/views/asdfs/index.html.erb:
372
- - "'sha256-SLp6LO3rrKDJwsG9uJUxZapb4Wp2Zhj6Bu3l+d9rnAY='"
373
- - "'sha256-HSGHqlRoKmHAGTAJ2Rq0piXX4CnEbOl1ArNd6ejp2TE='"
374
- ```
375
-
376
- ##### Helpers
377
-
378
- **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.
379
-
380
- ```erb
381
- <%= hashed_style_tag do %>
382
- body {
383
- background-color: black;
384
- }
385
- <% end %>
386
-
387
- <%= hashed_style_tag do %>
388
- body {
389
- font-size: 30px;
390
- font-color: green;
391
- }
392
- <% end %>
393
-
394
- <%= hashed_javascript_tag do %>
395
- console.log(1)
396
- <% end %>
397
- ```
398
-
399
- ```
400
- Content-Security-Policy: ...
401
- script-src 'sha256-yktKiAsZWmc8WpOyhnmhQoDf9G2dAZvuBBC+V0LGQhg=' ... ;
402
- style-src 'sha256-SLp6LO3rrKDJwsG9uJUxZapb4Wp2Zhj6Bu3l+d9rnAY=' 'sha256-HSGHqlRoKmHAGTAJ2Rq0piXX4CnEbOl1ArNd6ejp2TE=' ...;
403
- ```
404
-
405
- ### Public Key Pins
406
-
407
- 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.
408
-
409
- ```ruby
410
- config.hpkp = {
411
- max_age: 60.days.to_i, # max_age is a required parameter
412
- include_subdomains: true, # whether or not to apply pins to subdomains
413
- # Per the spec, SHA256 hashes are the only currently supported format.
414
- pins: [
415
- {sha256: 'b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c'},
416
- {sha256: '73a2c64f9545172c1195efb6616ca5f7afd1df6f245407cafb90de3998a1c97f'}
417
- ],
418
- report_only: true, # defaults to false (report-only mode)
419
- report_uri: 'https://report-uri.io/example-hpkp'
420
- }
421
- ```
422
-
423
- ### Cookies
424
-
425
- 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.
426
-
427
- __Note__: Regardless of the configuration specified, Secure cookies are only enabled for HTTPS requests.
428
-
429
- #### Boolean-based configuration
430
-
431
- Boolean-based configuration is intended to globally enable or disable a specific cookie attribute.
432
-
433
- ```ruby
434
- config.cookies = {
435
- secure: true, # mark all cookies as Secure
436
- httponly: false, # do not mark any cookies as HttpOnly
437
- }
438
- ```
439
-
440
- #### Hash-based configuration
441
-
442
- Hash-based configuration allows for fine-grained control.
443
-
444
- ```ruby
445
- config.cookies = {
446
- secure: { except: ['_guest'] }, # mark all but the `_guest` cookie as Secure
447
- httponly: { only: ['_rails_session'] }, # only mark the `_rails_session` cookie as HttpOnly
448
- }
449
- ```
450
-
451
- #### SameSite cookie configuration
452
-
453
- SameSite cookies permit either `Strict` or `Lax` enforcement mode options.
454
-
455
- ```ruby
456
- config.cookies = {
457
- samesite: {
458
- strict: true # mark all cookies as SameSite=Strict
459
- }
460
- }
461
- ```
462
-
463
- `Strict` and `Lax` enforcement modes can also be specified using a Hash.
464
-
465
- ```ruby
466
- config.cookies = {
467
- samesite: {
468
- strict: { only: ['_rails_session'] },
469
- lax: { only: ['_guest'] }
470
- }
471
- }
472
- ```
473
-
474
- ### Using with Sinatra
475
-
476
- Here's an example using SecureHeaders for Sinatra applications:
477
-
478
- ```ruby
479
- require 'rubygems'
480
- require 'sinatra'
481
- require 'haml'
482
- require 'secure_headers'
483
-
484
- use SecureHeaders::Middleware
485
-
486
- SecureHeaders::Configuration.default do |config|
487
- ...
488
- end
489
-
490
- class Donkey < Sinatra::Application
491
- set :root, APP_ROOT
492
-
493
- get '/' do
494
- SecureHeaders.override_x_frame_options(request, SecureHeaders::OPT_OUT)
495
- haml :index
496
- end
497
- end
498
- ```
499
147
 
500
148
  ## Similar libraries
501
149
 
@@ -509,6 +157,7 @@ end
509
157
  * Elixir [secure_headers](https://github.com/anotherhale/secure_headers)
510
158
  * Dropwizard [dropwizard-web-security](https://github.com/palantir/dropwizard-web-security)
511
159
  * Ember.js [ember-cli-content-security-policy](https://github.com/rwjblue/ember-cli-content-security-policy/)
160
+ * PHP [secure-headers](https://github.com/BePsvPT/secure-headers)
512
161
 
513
162
  ## License
514
163
 
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
+ ```