Skip to content
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

only use ephemeral storage for block 3p setting #7647

Merged
merged 10 commits into from
Jan 25, 2021
Merged

Conversation

bridiver
Copy link
Collaborator

@bridiver bridiver commented Jan 19, 2021

Resolves brave/brave-browser#12789

Submitter Checklist:

  • There is a ticket for my issue.
  • Used Github auto-closing keywords in the commit message.
  • Wrote a good PR/commit description
  • Added appropriate labels (QA/Yes or QA/No; release-notes/include or release-notes/exclude; OS/...) to the associated issue
  • Checked the PR locally: npm run test -- brave_browser_tests, npm run test -- brave_unit_tests, npm run lint, npm run gn_check, npm run tslint
  • Ran git rebase master (if needed).
  • Requested a security/privacy review as needed.

Reviewer Checklist:

  • New files have MPL-2.0 license header.
  • Adequate test coverage exists to prevent regressions
  • Major classes, functions and non-trivial code blocks are well-commented
  • Changes in component dependencies are properly reflected in gn
  • Code follows the style guide
  • Test plan is specified in PR before merging

After-merge Checklist:

Test Plan:

@bridiver bridiver requested a review from a team as a code owner January 19, 2021 00:43
@bridiver bridiver self-assigned this Jan 19, 2021
@bridiver bridiver changed the title only use ephemeral storage when for block 3p setting only use ephemeral storage for block 3p setting Jan 19, 2021
@bridiver
Copy link
Collaborator Author

still needs tests so technically a wip, but I wanted to get a build

@pes10k
Copy link
Contributor

pes10k commented Jan 19, 2021

just to keep everything stitched together, manual tests are here: https://dev-pages.brave.software/storage/ephemeral-storage.html

AllowStorageAccessForMainFrameSync(storage_type);
}

bool BraveContentSettingsAgentImpl::AllowStorageAccessSync(
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

still need to update the non-sync versions of these methods just for consistency in the results

session_storage_namespace_ = content::CreateSessionStorageNamespace(
partition, session_partition_id,
// clone the namespace if there is an opener
// https://html.spec.whatwg.org/multipage/browsers.html#copy-session-storage
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this clone copy non-ephemeral session storage data into the ephemeral session storage? I'm pretty sure that's why I didn't do this in the past.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it shouldn't be, I'm only passing the id of the parent session storage and it passes all the tests on https://dev-pages.brave.software/storage/ephemeral-storage.html

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and since the opener will be suppressed if it's not same domain the owner window will always have ephemeral storage enabled, but it might be worth adding a check in case there's some edge case with subdomains

Copy link
Collaborator Author

@bridiver bridiver Jan 21, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like it should be ok

// If the namespace doesn't exist or it's not populated yet, just create
      // an empty session storage by not marking it as pending a clone.
      if (clone_from_ns == namespaces_.end() ||
          !clone_from_ns->second->IsPopulated()) {
        break;
      }

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would be nice to have a browser test

bool block_3p = !cookie_settings->IsCookieAccessAllowed(
url, site_for_cookies, top_frame_origin);
bool block_1p = !cookie_settings->IsCookieAccessAllowed(
url, url, url::Origin::Create(url));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a clever way of doing this. Nice!

Comment on lines 165 to 169
// only use ephemeral storage for block 3p
if (block_3p && !block_1p)
return true;

return false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Here you could simply do:

return block_3p && !block_1p;

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yea, I could still attach the same comment to it for clarity so I'll clean that up

Comment on lines +10 to +11
bool IsEphemeralCookieAccessAllowed(const GURL& url, \
const GURL& first_party_url) const; \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you could eliminate this method by giving the three-argument version a default argument:

  bool IsEphemeralCookieAccessAllowed(                                    \
      const GURL& url, const GURL& site_for_cookies,                      \
      const base::Optional<url::Origin>& top_frame_origin = base::nullopt) const;   

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to stay consistent with the original methods for clarity

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and also when the two argument version is removed that might cause us to miss something

Comment on lines 72 to 90
if (use_ephemeral_storage) { \
auto top_frame_url = \
request_->isolation_info().top_frame_origin()->GetURL(); \
auto cookie_1p = net::CanonicalCookie::CreateSanitizedCookie( \
top_frame_url, cookie->Name(), cookie->Value(), cookie->Domain(), \
cookie->Path(), cookie->CreationDate(), cookie->ExpiryDate(), \
cookie->LastAccessDate(), cookie->IsSecure(), cookie->IsHttpOnly(), \
cookie->SameSite(), cookie->Priority(), cookie->IsSameParty()); \
\
net::CookieOptions::SameSiteCookieContext same_site_context = \
net::cookie_util::ComputeSameSiteContextForResponse( \
top_frame_url, request_->site_for_cookies(), \
request_->initiator(), false); \
net::CookieOptions options_1p = CreateCookieOptions(same_site_context); \
\
if (!(CanSetCookie(*cookie_1p, &options_1p) && \
!CanSetCookie(*cookie, &options))) \
use_ephemeral_storage = false; \
} \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can avoid duplicating this code by making it part of ShouldUseEphemeralStorage and passing in the cookie parameter.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yea, I think there are several places this can be cleaned up so I'll create some follow-up issues

Comment on lines +34 to +38
// only use ephemeral storage for block 3p
if (block_3p && !block_1p)
return true;

return false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could use the same simplification that I mentioned above.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MaybeClearAccessDeniedException(storage, *window, &exception_state);
if (!base::FeatureList::IsEnabled(net::features::kBraveEphemeralStorage))
if (!ShouldUseEphemeralStorage(
window, WebContentSettingsClient::StorageType::kSessionStorage))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be WebContentSettingsClient::StorageType::kLocalStorage instead? If not, can the argument be eliminated from the function entirely since each call site passes WebContentSettingsClient::StorageType::kSessionStorage?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. It won't affect anything because the ephemeral storage settings are the same for session and local storage, but it should be correct in case something changes with that in the future

net::CookieInclusionStatus returned_status; \
auto cookie = net::CanonicalCookie::Create( \
request_->url(), "a=a", base::Time::Now(), base::nullopt, \
&returned_status); \
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This param has a default value of nullptr and we don't seem to be using returned_status afterwords.

Copy link
Collaborator

@mkarolin mkarolin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

++ on chromium_src

@@ -8,6 +8,6 @@
namespace net {
namespace features {
const base::Feature kBraveEphemeralStorage{"EphemeralStorage",
base::FEATURE_DISABLED_BY_DEFAULT};
base::FEATURE_ENABLED_BY_DEFAULT};
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removing this change as it was not intentional

@@ -8,6 +8,7 @@

#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "base/strings/string16.h"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also base/containers/flat_map.h

auto* rfh = web_contents()->GetOpener();
session_storage_namespace_ = content::CreateSessionStorageNamespace(
partition, session_partition_id,
// clone the namespace if there is an opener
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

really a nit, but the style guide wants us to use proper punctuation, i.e. start sentenses with a capital and end with a dot.

https://google.github.io/styleguide/cppguide.html#Punctuation,_Spelling_and_Grammar

frame->GetDocument().TopFrameOrigin(),
url::Origin(frame->GetDocument().TopFrameOrigin()).GetURL(),
frame->GetDocument().TopFrameOrigin(), &result);
cached_storage_permissions_[key] = result;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need the cache at all? Growing it indefinitely looks pretty scary

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is copied from ContentSettingsAgentImpl and it's per-frame so it doesn't grow indefinitely

@iefremov
Copy link
Contributor

LGTM in general, but I'd like to understand whether we have tests for toggling the ephemeral storage on/off?

Also, should we explicitly delete existing ephemeral storage for a given domain when a user disables shields?

@iefremov
Copy link
Contributor

oops, something happened with network cookies

@bridiver
Copy link
Collaborator Author

@iefremov there are existing tests for cookie behavior that would break if ephemeral storage was turned on and I don't think we would delete the storage just because shields was disabled, but I'll defer to @pes10k

@pes10k
Copy link
Contributor

pes10k commented Jan 25, 2021

As long as the "when to clear the ephemeral storage" logic doesn't change, i dont think we need to "force clear" it when shields are dropped.

So, if i have two tabs, example.org/1.html and example.org/2.html w/ ephemeral storage enabled, and both pages have some thirdparty frame (e.g., third.org/frame.html). Even if i drop shields on example.org (so ephemeral storage is not being applied to the page), the <example.org, third.org> partition should be cleared when all example.org tabs are closed

@bridiver bridiver merged commit 3dc841e into master Jan 25, 2021
@bridiver bridiver deleted the ephemeral-storage branch January 25, 2021 19:46
@iefremov
Copy link
Contributor

@bridiver what happened to network cookies?..

@pes10k
Copy link
Contributor

pes10k commented Jan 25, 2021

We stripped it from the initial implementation bc (my understanding is) it made implementation much more complicated and ugly, and its by far the less important part of the system. It would still be very good to get it supported, but my preference was to not delay getting this 95%-of-the-benefit part shipped while we figure out whats possible network side.

@bridiver @iefremov if there isn't already a follow up issue for network navigation cookies, would you like me to create one?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Ephemeral storage should work when third-party cookies are blocked
5 participants