-
Notifications
You must be signed in to change notification settings - Fork 251
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Handle very dynamic policies better #232
Conversation
…configs we are modifying are dups of the originals
…ss. make cached_headers an attr_reader again
…st (and the cache is updated)
I suppose with this change you could argue that we only need to dup/operate on the header cache instead of maintaining a parallel config. Only the case of CSP do we operate on the config values without immediately modifying the header cache. The only reason to keep the config fields around is to lookup the value (e.g. the CSP config hash) and I'm not sure this would ever happen IRL, or at the least it would be an antipattern - business logic around what headers are currently configured should probably be handled in application code. |
This is ready for some 👀 if anyone has a moment. Note: this is a breaking API change - retrieving config values will only work for CSP and secure_cookies. I really can't see anyone working directly with a config object for the other headers and trying to retrieve their values. e.g. 💥 SecureHeaders.override(:my_override) do |config|
config.x_frame_options = config.x_frame_options == "sameorigin" ? "sameorigin" : "deny"
end No 💥 SecureHeaders.override(:my_override) do |config|
config.csp = config.csp.merge(:script_src => %w(data:)) # don't ever add data: to scriptsrc btw
end |
@@ -29,16 +29,14 @@ module SecureHeaders | |||
expect_default_values(header_hash) | |||
end | |||
|
|||
it "copies all config values except for the cached headers when dup" do | |||
it "copies config values when duping" do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given this PR is optimizing policy overrides are, I was surprised there was no test to validate that you are in fact only busting the cache once even if there are > 1 overrides. Does that seem a reasonable thing to add?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it also make sense to add a test to verify that overrides never end up touching csp
and only touch dynamic_csp
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a test here for the cache busting. I'll have to think about your second item.
Other than small test nits, this seems logical. 👍 |
…cy once, and modifies a local policy on subsequent modifications
Fixes #217
Currently, an idempotency check is performed for every policy addition. Not only does this create a fair number of temporary objects, but it also busts the entire header cache if any changes are detected.
This change defers idempotency checks until just before the header values are generated. If we can determine that the CSP will differ from the cached values, we discard all cached CSP and generate one specific to that UA.
If there is a change to
X-Frame-Options
, we cache the new value immediately.As a result, the value for
cached_headers
will always maintain the headers that will be applied and there is no need to generate them when callingheader_hash_for
.Because we are retaining the previously discarded cached headers, we only call
dup
on the configuration option if it isfrozen
to save bytes and cycles. All policies added viadefault
andoverride
are already frozen automatically, so a non-frozen
config object can be modified freely and we can assume it's dynamic in nature.To recap:
idempotent_additions?
called per policy modificationidempotent_additions?
called once per requestdup
'd per modificationdup
'd at most one time per request