-
Notifications
You must be signed in to change notification settings - Fork 894
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
Add partitioned HSTS storage support. #13062
Conversation
ca1f866
to
fdb6fc5
Compare
4c96f68
to
f73174a
Compare
Based on your description of the approach, it seems like the only time this change is a reduction in security is when dealing with an HTTP site that loads HTTP resources that can be upgraded to HTTPS via HSTS. So for example:
Before this change, the second visit (in Step 3) would have gone straight to HTTPS. With this change, the second visit will not know that the Facebook resource should be fetched on HTTPS and will attempt fetch the resource over HTTP first. It's worse from a security point of view, but that said, HTTP pages are already vulnerable to an on-path attacker changing the URLs of sub-resources prior to them being requested, so it's not a big deal. From a perf/memory point of view, if We could perhaps have an optimization where on an HTTPS page, we ignore any HSTS headers we see on sub-resources since they're not going to be needed on that page anyways, thanks to mixed-content blocking. It's not going to help with the HTTP case above, but at least it will reduce the number of unnecessary entries in the HSTS cache. |
What's the story with preloaded HSTS entries? Do they continue to apply (unpartitioned of course)? Can we perhaps add a test for this? |
preloaded HSTS entries lookup should work as usual, I've added tests to ensure it is.
I've looked into some options, but it's unclear what's the best approach here exactly, because we can break some tests that expect HSTS header is supported in these situations. |
I don't follow the breakage you have in mind here. Unless I'm misunderstanding something, if you're on an HTTPS page, then HSTS for any of the subresources is irrelevant because any HTTP resources would get blocked by the mixed content blocker, no? |
Yes, that's correct. I think you're right about not storing HSTS state in some situations, but what exact rules should we apply? For example, we have
Do we even care for any non-main frame HSTS headers when HSTS is partitioned? |
@goodov ideally we'd store as much HSTS state as possible. If its the case though that there are perf / memory limits here, then here is my rough preference of options:
|
I'm afraid there is not enough data to properly decide if HSTS data is worth storing or not (soon |
@goodov if the only options then are #1 or #4, what about a 2.5 option, something like: a. store all |
I had an in-memory storage for 3p frames initially (without cleanup on site close), but it added a noticeable amount of complexity during lookup and cleanup (reset HSTS if site wants to) phases even without the cleanup step on site close. The complexity can be solved by adding some conflict with upstream, but I decided not to go this way at that moment. If you think this will be beneficial, then I can look again at this, but if this is not crucial then I'd prefer to not introduce ES for HSTS. |
Gotcha, understood @goodov. Yes, i am fine with that tradeoff then. Thank you for talking through all the options with me. We are sacrificing some (broad) security and privacy (requests to HTTPS subresources can now be subjected to downgrade attacks) to gain a specific kind of privacy improvement (cross site tracking protection). I am fine with that tradeoff, as long as the security team is (cc @fmarier @diracdeltas ) |
If I understand correctly the proposed |
My original suggestion was not to drop from the cache entries that could be useful, but rather to remove the ones that aren't useful. If the top-level page is HTTPS, then we don't need to save HSTS signals we receive from the subresources because they're already getting blocked/upgraded by the mixed content blocker. Since HTTPS now covers the majority of page loads, this will likely be the bulk of the entries in the cache. |
I think thats mostly correct, but we would be reducing security in the following case
Im fine with the above trade off to gain useful-in-the-wild protections against cross-site-tracking, but i just wanted to try and explain where i see the trade off |
@@ -21,4 +22,118 @@ | |||
|
|||
#endif | |||
|
|||
#define BRAVE_TRANSPORT_SECURITY_STATE_DELETE_DYNAMIC_DATA_FOR_HOST \ |
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.
can we add unit tests for DeleteDynamicDataForHost to cover this?
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.
namespace net { | ||
|
||
// Implements partitioning support for structures in TransportSecurityState. | ||
class PartitionedHostStateMapBase { |
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.
can we add unit tests for this class?
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.
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.
I read through transport_security_state.cc
and I noted three more methods that may need to be partition-aware:
TransportSecurityState::NetLogUpgradeToSSLParam()
TransportSecurityState::AddHSTS()
(used innet-internals
)TransportSecurityState::GetDynamicSTSState()
(gets called byGetSTSState()
)
Let me know if you've already looked at them and left them out on purpose.
I do have one high-level question as well: what do we do with existing HSTS data when partitioning is enabled and disabled? In other words, once people upgrade an existing profile (with existing HSTS entries in the HSTS cache), does it mean that all existing entries will be ignored (and eventually expire) because the hashes won't match? That's probably what we want in order to clear any existing HSTS super-cookies, but it does mean that we have an additional (temporary) security downgrade, right? |
Is called directly from
This one I decided not to touch, because it was unclear how we can use it without additional UI changes (field for partition). But now I think that we can generate "top frame site" hash by taking eTLD+1 from the host we're trying to add. It makes sense and it should work. Yes, we still wouldn't be able to add partitioned HSTS records, but I think it's fine.
the data stays in the database, the lookup/store logic just creates different keys to operate it.
yes, we will have a temporary security downgrade with the current implementation. It might be possible to do a "legacy" lookup for cases when |
I discussed this with the rest of the security team and I don't think the extra complexity is worth it. After all, HSTS is not the only protection we have against downgrades, we also have HTTPS Everywhere. So we can just accept as a known limitation. It's a one-off event as well. |
b2feb03
to
48e726f
Compare
const std::string& host, | ||
STSState* result); | ||
|
||
// This is used only for manual addiing via net-internals page. |
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.
adding
@@ -0,0 +1,52 @@ | |||
/* Copyright 2021 The Brave Authors. All rights reserved. |
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.
2022 haha
…or_cookies doesn't match top_frame_site.
For the context: I tried to enable upstream brave-core/chromium_src/net/tools/transport_security_state_generator/input_file_parsers.cc Lines 365 to 376 in ca3e11d
|
Added partitioned HSTS storage support.
Original Chromium implementation uses
SHA256(domain)
as a key to store/lookup HSTS data fordomain
.Our implementation uses half of the original key and half of
SHA256(top_frame_etld1)
to partition HSTS data. This approach allows us to have partitioned storage and have the ability to cleanup HSTS by hostname looking only at first half of the hash.Originally I planned to use full
NetworkIsolationKey
which includestop_frame_site
andframe_site
, but initial tests showed pretty noticeable HSTS storage size just after a quick browsing session. I've also found a document that shows Chromium is moving away from triple-keying in favor of top-level site key only. Because of HSTS storage size concerns and upcoming upstream changes I went withtop_frame_site
as a partition key for HSTS.Resolves brave/brave-browser#18830
Submitter Checklist:
QA/Yes
orQA/No
;release-notes/include
orrelease-notes/exclude
;OS/...
) to the associated issuenpm run test -- brave_browser_tests
,npm run test -- brave_unit_tests
,npm run lint
,npm run gn_check
,npm run tslint
git rebase master
(if needed)Reviewer Checklist:
gn
After-merge Checklist:
changes has landed on
Test Plan: