secure_headers 6.3.1 → 7.1.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.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +20 -0
  3. data/Gemfile +3 -1
  4. data/README.md +22 -17
  5. data/lib/secure_headers/configuration.rb +11 -7
  6. data/lib/secure_headers/headers/clear_site_data.rb +4 -4
  7. data/lib/secure_headers/headers/content_security_policy.rb +25 -38
  8. data/lib/secure_headers/headers/content_security_policy_config.rb +17 -54
  9. data/lib/secure_headers/headers/cookie.rb +2 -2
  10. data/lib/secure_headers/headers/expect_certificate_transparency.rb +2 -2
  11. data/lib/secure_headers/headers/policy_management.rb +54 -12
  12. data/lib/secure_headers/headers/referrer_policy.rb +1 -1
  13. data/lib/secure_headers/headers/strict_transport_security.rb +1 -1
  14. data/lib/secure_headers/headers/x_content_type_options.rb +1 -1
  15. data/lib/secure_headers/headers/x_download_options.rb +2 -2
  16. data/lib/secure_headers/headers/x_frame_options.rb +1 -1
  17. data/lib/secure_headers/headers/x_permitted_cross_domain_policies.rb +2 -2
  18. data/lib/secure_headers/headers/x_xss_protection.rb +2 -2
  19. data/lib/secure_headers/railtie.rb +5 -5
  20. data/lib/secure_headers/version.rb +1 -1
  21. data/lib/secure_headers/view_helper.rb +7 -6
  22. data/lib/tasks/tasks.rake +6 -7
  23. data/secure_headers.gemspec +17 -7
  24. metadata +22 -67
  25. data/.github/ISSUE_TEMPLATE.md +0 -41
  26. data/.github/PULL_REQUEST_TEMPLATE.md +0 -20
  27. data/.github/workflows/build.yml +0 -24
  28. data/.github/workflows/sync.yml +0 -20
  29. data/.gitignore +0 -13
  30. data/.rspec +0 -3
  31. data/.rubocop.yml +0 -4
  32. data/.ruby-gemset +0 -1
  33. data/.ruby-version +0 -1
  34. data/CODE_OF_CONDUCT.md +0 -46
  35. data/CONTRIBUTING.md +0 -41
  36. data/Guardfile +0 -13
  37. data/Rakefile +0 -32
  38. data/docs/cookies.md +0 -65
  39. data/docs/hashes.md +0 -64
  40. data/docs/named_overrides_and_appends.md +0 -104
  41. data/docs/per_action_configuration.md +0 -141
  42. data/docs/sinatra.md +0 -25
  43. data/docs/upgrading-to-3-0.md +0 -42
  44. data/docs/upgrading-to-4-0.md +0 -35
  45. data/docs/upgrading-to-5-0.md +0 -15
  46. data/docs/upgrading-to-6-0.md +0 -50
  47. data/spec/lib/secure_headers/configuration_spec.rb +0 -121
  48. data/spec/lib/secure_headers/headers/clear_site_data_spec.rb +0 -87
  49. data/spec/lib/secure_headers/headers/content_security_policy_spec.rb +0 -165
  50. data/spec/lib/secure_headers/headers/cookie_spec.rb +0 -179
  51. data/spec/lib/secure_headers/headers/expect_certificate_transparency_spec.rb +0 -42
  52. data/spec/lib/secure_headers/headers/policy_management_spec.rb +0 -260
  53. data/spec/lib/secure_headers/headers/referrer_policy_spec.rb +0 -91
  54. data/spec/lib/secure_headers/headers/strict_transport_security_spec.rb +0 -33
  55. data/spec/lib/secure_headers/headers/x_content_type_options_spec.rb +0 -31
  56. data/spec/lib/secure_headers/headers/x_download_options_spec.rb +0 -29
  57. data/spec/lib/secure_headers/headers/x_frame_options_spec.rb +0 -36
  58. data/spec/lib/secure_headers/headers/x_permitted_cross_domain_policies_spec.rb +0 -48
  59. data/spec/lib/secure_headers/headers/x_xss_protection_spec.rb +0 -47
  60. data/spec/lib/secure_headers/middleware_spec.rb +0 -117
  61. data/spec/lib/secure_headers/view_helpers_spec.rb +0 -191
  62. data/spec/lib/secure_headers_spec.rb +0 -516
  63. data/spec/spec_helper.rb +0 -64
data/docs/hashes.md DELETED
@@ -1,64 +0,0 @@
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/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
- ```
@@ -1,104 +0,0 @@
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. Reusing a configuration name is not allowed and will throw an exception.
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
- end
80
-
81
- class MyController < ApplicationController
82
- def index
83
- # Produces default-src 'self'; script-src example.org otherdomain.com
84
- use_secure_headers_override(:script_from_otherdomain_com)
85
- end
86
-
87
- def show
88
- # Produces default-src 'self'; script-src example.org otherdomain.org evenanotherdomain.com
89
- use_secure_headers_override(:another_config)
90
- end
91
- end
92
- ```
93
-
94
- Reusing a configuration name is not allowed and will throw an exception.
95
-
96
- By default, a no-op configuration is provided. No headers will be set when this default override is used.
97
-
98
- ```ruby
99
- class MyController < ApplicationController
100
- def index
101
- SecureHeaders.opt_out_of_all_protection(request)
102
- end
103
- end
104
- ```
@@ -1,141 +0,0 @@
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
- <%= nonced_javascript_include_tag "include.js" %>
71
-
72
- <%= nonced_javascript_pack_tag "pack.js" %>
73
-
74
- <%= nonced_stylesheet_link_tag "link.css" %>
75
-
76
- <%= nonced_stylesheet_pack_tag "pack.css" %>
77
- ```
78
-
79
- becomes:
80
-
81
- ```html
82
- <script nonce="/jRAxuLJsDXAxqhNBB7gg7h55KETtDQBXe4ZL+xIXwI=">
83
- console.log("nonced!")
84
- </script>
85
- <style nonce="/jRAxuLJsDXAxqhNBB7gg7h55KETtDQBXe4ZL+xIXwI=">
86
- body {
87
- background-color: black;
88
- }
89
- </style>
90
- ```
91
-
92
- ```
93
-
94
- Content-Security-Policy: ...
95
- script-src 'nonce-/jRAxuLJsDXAxqhNBB7gg7h55KETtDQBXe4ZL+xIXwI=' ...;
96
- style-src 'nonce-/jRAxuLJsDXAxqhNBB7gg7h55KETtDQBXe4ZL+xIXwI=' ...;
97
- ```
98
-
99
- `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.
100
-
101
- ```erb
102
- <script nonce="<%= content_security_policy_script_nonce %>">
103
- console.log("whitelisted, will execute")
104
- </script>
105
-
106
- <script nonce="lol">
107
- console.log("won't execute, not whitelisted")
108
- </script>
109
-
110
- <script>
111
- console.log("won't execute, not whitelisted")
112
- </script>
113
- ```
114
-
115
- ## Clearing browser cache
116
-
117
- You can clear the browser cache after the logout request by using the following.
118
-
119
- ``` ruby
120
- class ApplicationController < ActionController::Base
121
- # Configuration override to send the Clear-Site-Data header.
122
- SecureHeaders::Configuration.override(:clear_browser_cache) do |config|
123
- config.clear_site_data = [
124
- SecureHeaders::ClearSiteData::ALL_TYPES
125
- ]
126
- end
127
-
128
-
129
- # Clears the browser's cache for browsers supporting the Clear-Site-Data
130
- # header.
131
- #
132
- # Returns nothing.
133
- def clear_browser_cache
134
- SecureHeaders.use_secure_headers_override(request, :clear_browser_cache)
135
- end
136
- end
137
-
138
- class SessionsController < ApplicationController
139
- after_action :clear_browser_cache, only: :destroy
140
- end
141
- ```
data/docs/sinatra.md DELETED
@@ -1,25 +0,0 @@
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
- ```
@@ -1,42 +0,0 @@
1
- `secure_headers` 3.0 is a near-complete rewrite. It includes breaking changes and removes a lot of features that were either leftover from the days when the CSP standard was not fully adopted or were just downright confusing.
2
-
3
- Changes
4
- ==
5
-
6
- | What | < = 2.x | >= 3.0 |
7
- | ---------------------------------- | ---------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
8
- | Global configuration | `SecureHeaders::Configuration.configure` block | `SecureHeaders::Configuration.default` block |
9
- | All headers besides HPKP and CSP | Accept hashes as config values | Must be strings (validated during configuration) |
10
- | CSP directive values | Accepted space delimited strings OR arrays of strings | Must be arrays of strings |
11
- | CSP Nonce values in views | `@content_security_policy_nonce` | `content_security_policy_nonce(:script)` or `content_security_policy_nonce(:style)` |
12
- | nonce is no longer a source expression | `config.csp = "'self' 'nonce'"` | Remove `'nonce'` from source expression and use [nonce helpers](https://github.com/twitter/secureheaders#nonce). |
13
- | `self`/`none` source expressions | Could be `self` / `none` / `'self'` / `'none'` | Must be `'self'` or `'none'` |
14
- | `inline` / `eval` source expressions | Could be `inline`, `eval`, `'unsafe-inline'`, or `'unsafe-eval'` | Must be `'unsafe-eval'` or `'unsafe-inline'` |
15
- | Per-action configuration | Override [`def secure_header_options_for(header, options)`](https://github.com/twitter/secureheaders/commit/bb9ebc6c12a677aad29af8e0f08ffd1def56efec#diff-04c6e90faac2675aa89e2176d2eec7d8R111) | Use [named overrides](https://github.com/twitter/secureheaders#named-overrides) or [per-action helpers](https://github.com/twitter/secureheaders#per-action-configuration) |
16
- | CSP/HPKP use `report_only` config that defaults to false | `enforce: false` | `report_only: false` |
17
- | Schemes in source expressions | Schemes were not stripped | Schemes are stripped by default to discourage mixed content. Setting `preserve_schemes: true` will revert to previous behavior |
18
- | Opting out of default configuration | `skip_before_filter :set_x_download_options_header` or `config.x_download_options = false` | Within default block: `config.x_download_options = SecureHeaders::OPT_OUT` |
19
-
20
- Migrating to 3.x from <= 2.x
21
- ==
22
-
23
- 1. Convert all headers except for CSP/HPKP using hashes to string values. The values are validated at runtime and will provide guidance on misconfigured headers.
24
- 1. Convert all instances of `self`/`none`/`eval`/`inline` to the corresponding values in the above table.
25
- 1. Convert all CSP space-delimited directives to an array of strings.
26
- 1. Convert all `enforce: true|false` to `report_only: true|false`.
27
- 1. Remove `ensure_security_headers` from controllers (3.x uses a middleware instead).
28
-
29
- Everything is terrible, why should I upgrade?
30
- ==
31
-
32
- `secure_headers` <= 2.x built every header per request using a series of automatically included `before_filters`. This is horribly inefficient because:
33
-
34
- 1. `before_filters` are slow and adding 8 per request isn't great
35
- 1. We are rebuilding strings that may never change for every request
36
- 1. Errors in the request may mean that the headers never get set in the first place
37
-
38
- `secure_headers` 3.x sets headers in rack middleware that runs once per request and uses configuration values passed via `request.env`. This is much more efficient and somewhat guarantees that headers will always be set. **The values for the headers are cached and reused per request**.
39
-
40
- Also, there is a more flexible API for customizing content security policies / X-Frame-Options. In practice, none of the other headers need granular controls. One way of customizing headers per request is to use the helper methods. The only downside of this technique is that headers will be computed from scratch.
41
-
42
- See the [README](README.md) for more information.
@@ -1,35 +0,0 @@
1
- ## script_src must be set
2
-
3
- Not setting a `script_src` value means your policy falls back to whatever `default_src` (also required) is set to. This can be very dangerous and indicates the policy is too loose.
4
-
5
- However, sometimes you really don't need a `script-src` e.g. API responses (`default-src 'none'`) so you can set `script_src: SecureHeaders::OPT_OUT` to work around this.
6
-
7
- ## Default Content Security Policy
8
-
9
- The default CSP has changed to be more universal without sacrificing too much security.
10
-
11
- * Flash/Java disabled by default
12
- * `img-src` allows data: images and favicons (among others)
13
- * `style-src` allows inline CSS by default (most find it impossible/impractical to remove inline content today)
14
- * `form-action` (not governed by `default-src`, practically treated as `*`) is set to `'self'`
15
-
16
- Previously, the default CSP was:
17
-
18
- `Content-Security-Policy: default-src 'self'`
19
-
20
- The new default policy is:
21
-
22
- `default-src https:; form-action 'self'; img-src https: data: 'self'; object-src 'none'; script-src https:; style-src 'self' 'unsafe-inline' https:`
23
-
24
- ## CSP configuration
25
-
26
- * Setting `report_only: true` in a CSP config will raise an error. Instead, set `csp_report_only`.
27
- * Setting `frame_src` and `child_src` when values don't match will raise an error. Just use `frame_src`.
28
-
29
- ## config.secure_cookies removed
30
-
31
- Use `config.cookies` instead.
32
-
33
- ## Supported ruby versions
34
-
35
- We've dropped support for ruby versions <= 2.2. Sorry.
@@ -1,15 +0,0 @@
1
- ## All cookies default to secure/httponly/SameSite=Lax
2
-
3
- By default, *all* cookies will be marked as `SameSite=lax`,`secure`, and `httponly`. To opt-out, supply `SecureHeaders::OPT_OUT` as the value for `SecureHeaders.cookies` or the individual configs. Setting these values to `false` will raise an error.
4
-
5
- ```ruby
6
- # specific opt outs
7
- config.cookies = {
8
- secure: SecureHeaders::OPT_OUT,
9
- httponly: SecureHeaders::OPT_OUT,
10
- samesite: SecureHeaders::OPT_OUT,
11
- }
12
-
13
- # nuclear option, just make things work again
14
- config.cookies = SecureHeaders::OPT_OUT
15
- ```
@@ -1,50 +0,0 @@
1
- ## Named overrides are now dynamically applied
2
-
3
- The original implementation of name overrides worked by making a copy of the default policy, applying the overrides, and storing the result for later use. But, this lead to unexpected results if named overrides were combined with a dynamic policy change. If a change was made to the default configuration during a request, followed by a named override, the dynamic changes would be lost. To keep things consistent named overrides have been rewritten to work the same as named appends in that they always operate on the configuration for the current request. As an example:
4
-
5
- ```ruby
6
- class ApplicationController < ActionController::Base
7
- Configuration.default do |config|
8
- config.x_frame_options = SecureHeaders::OPT_OUT
9
- end
10
-
11
- SecureHeaders::Configuration.override(:dynamic_override) do |config|
12
- config.x_content_type_options = "nosniff"
13
- end
14
- end
15
-
16
- class FooController < ApplicationController
17
- def bar
18
- # Dynamically update the default config for this request
19
- override_x_frame_options("DENY")
20
- append_content_security_policy_directives(frame_src: "3rdpartyprovider.com")
21
-
22
- # Override everything, discard modifications above
23
- use_secure_headers_override(:dynamic_override)
24
- end
25
- end
26
- ```
27
-
28
- Prior to 6.0.0, the response would NOT include a `X-Frame-Options` header since the named override would be a copy of the default configuration, but with `X-Content-Type-Options` set to `nosniff`. As of 6.0.0, the above code results in both `X-Frame-Options` set to `DENY` AND `X-Content-Type-Options` set to `nosniff`.
29
-
30
- ## `ContentSecurityPolicyConfig#merge` and `ContentSecurityPolicyReportOnlyConfig#merge` work more like `Hash#merge`
31
-
32
- These classes are typically not directly instantiated by users of SecureHeaders. But, if you access `config.csp` you end up accessing one of these objects. Prior to 6.0.0, `#merge` worked more like `#append` in that it would combine policies (i.e. if both policies contained the same key the values would be combined rather than overwritten). This was not consistent with `#merge!`, which worked more like ruby's `Hash#merge!` (overwriting duplicate keys). As of 6.0.0, `#merge` works the same as `#merge!`, but returns a new object instead of mutating `self`.
33
-
34
- ## `Configuration#get` has been removed
35
-
36
- This method is not typically directly called by users of SecureHeaders. Given that named overrides are no longer statically stored, fetching them no longer makes sense.
37
-
38
- ## Configuration headers are no longer cached
39
-
40
- Prior to 6.0.0 SecureHeaders pre-built and cached the headers that corresponded to the default configuration. The same was also done for named overrides. However, now that named overrides are applied dynamically, those can no longer be cached. As a result, caching has been removed in the name of simplicity. Some micro-benchmarks indicate this shouldn't be a performance problem and will help to eliminate a class of bugs entirely.
41
-
42
- ## Configuration the default configuration more than once will result in an Exception
43
-
44
- Prior to 6.0.0 you could conceivably, though unlikely, have `Configure#default` called more than once. Because configurations are dynamic, configuring more than once could result in unexpected behavior. So, as of 6.0.0 we raise `AlreadyConfiguredError` if the default configuration is setup more than once.
45
-
46
- ## All user agent sniffing has been removed
47
-
48
- The policy configured is the policy that is delivered in terms of which directives are sent. We still dedup, strip schemes, and look for other optimizations but we will not e.g. conditionally send `frame-src` / `child-src` or apply `nonce`s / `unsafe-inline`.
49
-
50
- The primary reason for these per-browser customization was to reduce console warnings. This has lead to many bugs and results inc confusing behavior. Also, console logs are incredibly noisy today and increasingly warn you about perfectly valid things (like sending `X-Frame-Options` and `frame-ancestors` together).
@@ -1,121 +0,0 @@
1
- # frozen_string_literal: true
2
- require "spec_helper"
3
-
4
- module SecureHeaders
5
- describe Configuration do
6
- before(:each) do
7
- reset_config
8
- end
9
-
10
- it "has a default config" do
11
- expect(Configuration.default).to_not be_nil
12
- end
13
-
14
- it "has an 'noop' override" do
15
- Configuration.default
16
- expect(Configuration.overrides(Configuration::NOOP_OVERRIDE)).to_not be_nil
17
- end
18
-
19
- it "dup results in a copy of the default config" do
20
- Configuration.default
21
- original_configuration = Configuration.send(:default_config)
22
- configuration = Configuration.dup
23
- expect(original_configuration).not_to be(configuration)
24
- Configuration::CONFIG_ATTRIBUTES.each do |attr|
25
- expect(original_configuration.send(attr)).to eq(configuration.send(attr))
26
- end
27
- end
28
-
29
- it "stores an override" do
30
- Configuration.override(:test_override) do |config|
31
- config.x_frame_options = "DENY"
32
- end
33
-
34
- expect(Configuration.overrides(:test_override)).to_not be_nil
35
- end
36
-
37
- describe "#override" do
38
- it "raises on configuring an existing override" do
39
- set_override = Proc.new {
40
- Configuration.override(:test_override) do |config|
41
- config.x_frame_options = "DENY"
42
- end
43
- }
44
-
45
- set_override.call
46
-
47
- expect { set_override.call }
48
- .to raise_error(Configuration::AlreadyConfiguredError, "Configuration already exists")
49
- end
50
-
51
- it "raises when a named append with the given name exists" do
52
- Configuration.named_append(:test_override) do |config|
53
- config.x_frame_options = "DENY"
54
- end
55
-
56
- expect do
57
- Configuration.override(:test_override) do |config|
58
- config.x_frame_options = "SAMEORIGIN"
59
- end
60
- end.to raise_error(Configuration::AlreadyConfiguredError, "Configuration already exists")
61
- end
62
- end
63
-
64
- describe "#named_append" do
65
- it "raises on configuring an existing append" do
66
- set_override = Proc.new {
67
- Configuration.named_append(:test_override) do |config|
68
- config.x_frame_options = "DENY"
69
- end
70
- }
71
-
72
- set_override.call
73
-
74
- expect { set_override.call }
75
- .to raise_error(Configuration::AlreadyConfiguredError, "Configuration already exists")
76
- end
77
-
78
- it "raises when an override with the given name exists" do
79
- Configuration.override(:test_override) do |config|
80
- config.x_frame_options = "DENY"
81
- end
82
-
83
- expect do
84
- Configuration.named_append(:test_override) do |config|
85
- config.x_frame_options = "SAMEORIGIN"
86
- end
87
- end.to raise_error(Configuration::AlreadyConfiguredError, "Configuration already exists")
88
- end
89
- end
90
-
91
- it "deprecates the secure_cookies configuration" do
92
- expect {
93
- Configuration.default do |config|
94
- config.secure_cookies = true
95
- end
96
- }.to raise_error(ArgumentError)
97
- end
98
-
99
- it "gives cookies a default config" do
100
- expect(Configuration.default.cookies).to eq({httponly: true, secure: true, samesite: {lax: true}})
101
- end
102
-
103
- it "allows OPT_OUT" do
104
- Configuration.default do |config|
105
- config.cookies = OPT_OUT
106
- end
107
-
108
- config = Configuration.dup
109
- expect(config.cookies).to eq(OPT_OUT)
110
- end
111
-
112
- it "allows me to be explicit too" do
113
- Configuration.default do |config|
114
- config.cookies = {httponly: true, secure: true, samesite: {lax: false}}
115
- end
116
-
117
- config = Configuration.dup
118
- expect(config.cookies).to eq({httponly: true, secure: true, samesite: {lax: false}})
119
- end
120
- end
121
- end