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.
What | < = 2.x | >= 3.0 |
---|---|---|
Global configuration | SecureHeaders::Configuration.configure block |
SecureHeaders::Configuration.default block |
All headers besides HPKP and CSP | Accept hashes as config values | Must be strings (validated during configuration) |
CSP directive values | Accepted space delimited strings OR arrays of strings | Must be arrays of strings |
self /none source expressions |
could be self / none / 'self' / 'none' |
Must be 'self' or 'none' |
inline / eval source expressions |
could be inline , eval , 'unsafe-inline' , or 'unsafe-eval' |
Must be 'unsafe-eval' or 'unsafe-inline' |
Per-action configuration | override def secure_header_options_for(header, options) |
Use named overrides or per-action helpers |
- 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.
- Convert all instances of
self
/none
/eval
/inline
to the corresponding values in the above table. - Convert all CSP space-delimited directives to an array of strings.
secure_headers
<= 2.x built every header per request using a series of automatically included before_filters
. This is horribly inefficient because:
before_filters
are slow and adding 8 per request isn't great- We are rebuilding strings that may never change for every request
- Errors in the request may mean that the headers never get set in the first place
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.
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.
See the README for more information.