-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Proposal: Storage Access API #3338
Comments
Can you please elaborate on what is meant by...
How is the partitioning of the cookies affected by calling requestStorageAccess()? Thanks in advance. |
That is, as you can see, a WebKit-specific detail and not really part of what we propose. But sure. Let's say example.com has an iframe from social.org and social.org's cookies are partitioned under example.com. If the social.org iframe calls document.requestStorageAccess() upon a user gesture, and the rules say that access should be granted, the returned promise will resolve. From that point, social.org's cookies are no longer partitioned under example.com in that iframe. Instead it has access to whatever cookies it would have if the user went directly to social.org as a first-party website. Access goes back to its partitioned state when social.org's document in that iframe goes away or its frame is detached from the DOM. The same would apply to any other partitioned storage that the browser supports in Storage Access API. |
Small note on "access to whatever cookies it would have if the user went directly to social.org as a first-party website": That obviously wouldn't apply to SameSite cookies. WebKit don't support those yet, but I wanted to mention that exception. |
We ran into the partitioned storage problem when writing polyfills for the Payment Handler API and Credential Handler APIs and running them on Safari. These needed to load content via a third-party iframe that maintained previously registered payment and credential handlers that were kept track of via localStorage/IndexedDB. When the relying party website (that loaded the polyfill iframe) attempted to request payment or credentials on Safari, the iframe would fail to see what the user previously registered -- and there was no way to fulfill the request. It sounds like this API would address the problem, which would be fantastic. |
As I mentioned at TPAC, Chrome offers granular cookie & site data controls and UI that allow for users configuring this without any special APIs, so I'm a bit surprised that we'd need to change the spec for something that other browsers already can offer. I'm also not sure why we'd need a separate API for this as opposed to using the permissions API. |
Are you saying Chrome has cookie controls that allow the user to block or partition all or some cross-origin resources’ cookies, and then allow those subresources cookie access on a per-iframe or per page basis? |
Browsers can offer the functionality natively, but it might be reasonable to give sites the ability to ask for more permission than they're granted as-configured. In the same way that the permission API gives sites the ability to ask for geolocation, even when the browser is configured to deny-by-default, the problem statement above posits that it might be reasonable to allow sites to ask for permission to access locally stored data, even if the existing configuration would deny that to them. If we model storage as a permission, as @jyasskin suggested elsewhere, it doesn't seem out of the question to me that developers could call something like Also, as @annevk noted in the DOM bug, and @raymeskhoury has noted in a Permission Delegation proposal prompting from a third-party context is hard. It's interesting to think about some of the secondary consequences of modeling this as a permission, if some browsers are shifting to a world where we deny third-party permissions by default and allow/require the parent to delegate. Requiring |
Mike, do you still think the API should be on navigator given that any access is scoped to the document? |
To explain the context for this a bit more, I'd like to explain some things about Safari's current storage policy for third-party contexts, and also some model use cases for this proposed storage access API. I think some of the suggestions here may be due to lack of clarity about these things. Safari's third-party storage policySafari has long partitioned or denied all types of storage except cookies, including even incidental storage like the cache, to prevent tracking via so-called super cookies like evercookie. Partitioning means keying based on both the origin of the resource and the top-level document's origin, effectively making third-party contexts see completely different storage universes on each site they were embedded into. Cookies were an exception, for web compatibility reasons. Cookies were partially blocked via our long-standing policy that prevents setting new third-party cookies. But if a third-party cookie already existed, third-party origins could read and set it. In 2017, we extended this to also partition cookies in third-party contexts (with a few limited exceptions). As a result, most content has access to only a partitioned view of its storage including cookies. The reason for all this is privacy. We don't want embedded content to be able to passively track users across the web. We're most interested in preventing passive tracking, not necessarily incidental tracking when a user chooses to engage with a cross-site embed. Use cases
How the Storage Access API helps with cases like thisWhen the user clicks on a YouTube video to play it, or a Facebook like button to like an article, the embedded content may In the examples above, this would allow YouTube to respect the user's settings, and Facebook to know who they are to register the "like". However, it would not enable passive tracking. The user has to click every time to expose first-party state. Why some other ideas in this issue would not work
How this might apply to other browsersOther browsers, including Mozilla and Brave, have expressed interest in denying storage to third-party origins either by default or in optional modes. We believe this API could allow embedded gadgets to function correctly under these types of policies. |
Would the choice be remembered on the same site in the future without user interaction? I imagine not -- which has me wondering how this would impact embedded content that only loads after the user has engaged in some activity on the top-level domain. For example, consider a payment handler polyfill that shows the user their registered payment handlers for selection after they've hit a pay button on the top level domain. With storage partitioning enabled and this new API, the registered payment handlers would be inaccessible (being stored in localStorage/IndexedDB by a third-party polyfill domain) until the user clicks on the embedded content. This may be acceptable the first time it happens, by adding a one-time prompt requesting that the user enable payment on the site. But introducing an extra click to the payment process every time they buy something from the same site would be unfortunate. It would also be unfortunate to force the top-level domain to use a specialized payment button that is served from the third-party polyfill domain as a mitigation to this problem. One of the advantages of standardizing payment on the Web is to avoid the Nascar problem and forcing top-level domains to use specialized buttons. I wonder if some kind of one-time use "delegated user interaction object" could be passed to the iframe via |
No.
I don't think it would help in such cases (unless the user clicks again on the embedded content).
Do you know a real site or embedded gadget that actually works this way? It would specifically need to:
I don't know of any setups like this, but if there are, we can certainly think about opportunities to help them in the face of limitations on third-party storage. |
Other than the payment handler and credential handler polyfills -- I don't know of any at the moment. There may be some some third-party payment providers that provide this kind of flow, but I'm unaware of them. This is the payment handler polyfill demo that was presented at TPAC that I'm talking about (note that this won't run in Safari because of this very issue, but will run in Chrome, Firefox, and Edge): You install a payment handler and add payment instruments (credit cards) here at a "wallet" website: https://payment-handler.demo.digitalbazaar.com/ And then you use the registered handler here via a payment instrument of your choice here at a "merchant" website: https://payment-merchant.demo.digitalbazaar.com/ This follows the flow you described above. |
It does seem like that demo would need to be modified even with this new API in place. It will either need an extra click to look up the default payment method, or the buy button itself needs to be an iframe. Since this demo is not (as far as I know) in wide actual use, I am not sure it should be a priority to design around its requirements rather than to look at ways to modify the demo. |
Thanks, @johnwilander and @othermaciej for the detailed background. That's helpful information. I'll pull out a few points below:
If we model things as a permission, then I think hooking into the existing
I think this addresses some of the use cases you noted above, while partially addressing others. Video sites are good examples of embeds that need to make decisions about what content to show a given user prior user interaction in order to comply with a user's preferences regarding mature content (Vimeo's viewing preferences, YouTube's restricted mode, etc.). It seems like this mechanism might push some of those sites into a client-side rendering model whereby content is locked behind a clickthrough that calls out to the mechanism y'all are proposing before rendering anything. That seems doable from a technical perspective, but would have performance (and aesthetic!) impacts on users.
All of these restrictions would be compatible with treating storage access as a permission that the browser makes decisions about whether to grant or restrict, with or without user interaction. The scoping and persistence is a bit different than we've done with other permissions in the past (and different still from what Chrome folks are proposing), but the core notion of asking first, and then doing, seems like a reasonable fit.
It's somewhat tangential to the core proposal, but I'd suggest that y'all will want to consider whether or not the user gesture is consumed by the call to obtain first-party storage. I know that Chrome's gesture implementation has sometimes caused developers some annoyance by disallowing combinations of actions with a single gesture. I can imagine that applying here as well: perhaps a widget would ask for credentials on click, and use them to make a decision about whether to call
Chrome's content settings are certainly capable of making this distinction between "B in A" and "B in C" (see the Primary and Secondary Patterns section of the
I know that some users (like @jeisinger above :) ) have developed workflows whereby they toggle Chrome's "Block third-party cookies and site data" option, and then make use of the omnibox UX and the reload button to fix sites after visiting them. It seems to me that that's not a terrible model.
Another way of looking at the same mechanism would be that the top-level document would be able to use Feature Policy to deny access to certain permissions to its children by fiat, the embeddee's wishes notwithstanding. Moreover, even in a fully realized delegation model, the browser remains in a position of mediating the permission requests, and could certainly make a decision about whether to grant permissions on the basis of information to which the page isn't privy. The permission model means that the request would fall into a well-paved API path for developers, not that you'd be locked into adhering to a page's desires without the potential for override.
/cc @TanviHacks, @dveditz, @diracdeltas from those browsers for feedback. Also tagging in @patrickkettner to get Edge in the loop. |
Hi, Yan from Brave here! Brave does indeed block 3rd party storage (cookies, localStorage, etc.) and referrer by default.
We (Brave) would almost certainly want to prompt by default with a 'never prompt again' option in the permissions UX. I think this API would be useful but we would want to be careful to not make our current cookie restrictions more lax without alerting the user. |
@diracdeltas The API is designed to allow all the prompting you want (since it's async) so it would be easy to fulfill it with a prompt-always (or prompt-once-per-origin-pair) policy. |
Yes, it would be great to allow for never prompting again. Many integrations that involve data sharing are moving towards a more granular model of permissions, with an emphasis on prompting only in context and as needed, rather than asking for all permissions that might ever be needed up front. The more friction the browser adds to this, the less likely sites are to adopt these granular and just-in-time models. |
From today's W3C WebAppSec call, as I interpreted it:
|
@johnwilander For now, Brave's status is that we would use this if it were already implemented in Chromium. We could be interested in implementing it independent of Chromium depending on adoption. |
What I hope I suggested on the call was that I don't think Chrome has a concrete interest in implementing this, but that if a Chromium port (like Brave) wanted to upstream a patch to reduce their maintenance burden, I'd be happy to help them do so. The WebAppSec discussion's draft minutes are available at https://www.w3.org/2018/01/17-webappsec-minutes.html#item04 if folks here are interested in the points raised there. @dveditz and I re-raised the suggestion that this might fit into the Permissions API rather than building a new one-off on |
The "has" method can be modeled as a permission I think. "Request" not so much. FWIW, there's quite a few people within Mozilla that have a problem with prompts on behalf of third-parties and I'm not really sure how to reconcile that position with this API. |
I agree. One of the earlier suggestions in this thread was to tie the request bit to a new method on
That's also something Chrome folks are reluctant to do more of. |
As for prompting, it’s optional in the proposal. Are you saying you’re against optional prompting too? Brave expressed that they’ll definitely prompt. We want the ability if we see abuse of the API down the road. |
The @privacycg has adopted this as a work item; instead of trying to cover all of the issues with the API in this one issue, everyone can now file issues over there: https://github.com/privacycg/storage-access/issues |
👆🏼What Tess said. We've moved this to the W3C Privacy CG where you can file individual issues on the things you want to discuss: https://github.com/privacycg/storage-access Thanks for all the engagement we got on this lengthy issue! I will now close it. Eventually we should expect a pull request on the HTML spec. |
Reopening as WHATWG likes to keep track of activity that will eventually be upstreamed through open issues. Hope that's understandable. |
Maybe a better approach would be to edit the initial comment to prominently point to the privacycg issue tracker where work is happening for now? |
Done. |
Thanks, Anne! |
After reading all of the above specification and pondering on its effects on real applications I think that if one needs non ephemeral non partitioned local storage for any purpose other thank tracking there's no real way of having it granted even if the user would otherwise want to grant it. LocalStorage purpose is to save large amounts of data and have the data not leave the browser (be it for logistical purposes or security for that matter ... and I won't go in details on how important is the latter...) There's a plethora of applications that work based on this presumption ... say for example an application that has multiple subdomains and users have copyrighted art they work on with various tools presented to them on different websites. The purpose is that the data never leaves their browser so the data is not copied nor exposed to any party attempting to copy it, not to mention that such data is large enough to begin with that it would not make sense to send over the wire. For all of the above and the presented example, I think that the only proper implementation is the one made in Firefox meanwhile the Safari version is at the very least abysmally unthought about ... if there's anything nice to say about it ... And to make things even worse the Firefox implementation already has other security measures and partitioning in place the (read here TLS Security keys, HSTS etc ) which I don't know whether Apple and your Safari (speaking mainly to you @johnwilander) has even had a glimpse about, so the only thing Safari stops is properly implemented applications that have the security of their users at heart meanwhile protecting shamelessly the very thing they claim to work against. In all honesty I think that at the very least this initiative should be approached with giving the user the ability to grant localStorage access even if it is after being prompted for it. |
Hi @valipopescu! First of all, the Storage Access API is worked on in the W3C Privacy CG since a couple of years: https://github.com/privacycg/storage-access. It'll eventually find its way into specs such as HTML but the Privacy CG is the right place to discuss it. Second, in standards repos like this, we try not to discuss browser-specific things that are not proposed standards. You can file a bug with the particular browser or engine if you want to raise such issues. Finally, I believe you are mistaken on WebKit's partitioning and tracking prevention, based on what you write above. Please see https://webkit.org/tracking-prevention/. |
Thanks for the swift response, which I highly appreciate. I haven't been able to find a way to report the implementation of the Tracking prevention as you call it in webkit, as a bug per se. Since I found that you were the proposal main as well as responsible for the webkit tracking prevention, would appreciate a way for us to present in detail what's going on and maybe you can suggest the way Apple Webkit has thought about how to handle such situations. This is once again related to actual user security rather than tracking. |
You are always welcome to file bugs at https://bugs.webkit.org and CC me. Please use the Security bug category for privacy/security bugs. Thanks! (The other engines have open source bug trackers too in case you wanted to file for them too.) |
The spec say's:
Link: https://privacycg.github.io/storage-access/#permissions-policy-integration Yet in the Chromium source code says: Just wondering if there is an issue in the spec or not? Or is the code in Chromium wrong? Will open an issue: privacycg/storage-access#104 |
Details to be discussed in the W3C Privacy CG
We've moved this to the W3C Privacy CG where you can file individual issues on the things you want to discuss: https://github.com/privacycg/storage-access
Original issue
Hi! John Wilander from WebKit here. We hope this can extend existing specifications rather than create some whole new spec. It was originally filed under whatwg/dom but I was advised to move it here.
Storage Access API
Problem
Tl;dr: Browsers that block access to third-party cookies break authenticated embeds such as commenting widgets and subscribed video services.
In the context of cross-origin resource loads, cookies are popularly referred to as third-party cookies. In reality, these cookies are often the same as the first-party cookies so what we really mean with third-party cookies is access to first-party cookies in a third-party context.
A browser may have rules for third-party cookies that go beyond cookie policy rules such as scheme, host, path, secure attribute etc. These additional rules may be:
However, certain services are intended to be embedded as third-party content and need access to first-party cookies for authentication. Examples are commenting widgets, video embeds, payment provider integration, document embeds, and social media action widgets. These break if the third-party content has no access to its first-party cookies.
The same problem exists for other kinds of storage such as IndexedDB and LocalStorage, except they are not tied to the HTTP protocol and are typically not used for authentication purposes. From here on we will refer to cookies except when the distinction between cookies and other storage makes sense.
Proposed Solution
Tl;dr: A new API with which cross-origin iframes can request access to their first-party cookies when processing a user gesture such as a tap or a click. This allows third-party embeds to authenticate on user interaction.
We propose two new functions on the document:
The reasons these are on the document is that 1) storage access is granted to the particular document (see Access Removal) and 2) it changes document.cookie.
hasStorageAccess() can be called at any time to check whether access is already granted and it doesn't require user interaction.
requestStorageAccess() should only be called on user interaction such as a tap or a click. It will check a set of rules and grant access if the rules are fulfilled. Access to first-party cookies in the given iframe can be assumed if the returned promise resolves. From that point, any sub resource load in the iframe will have first-party cookies sent and incoming cookies will be set in the first-party cookie jar.
Note that no other third-party resources on that webpage are affected by the storage access status of an individual iframe.
Algorithm for requestStorageAccess()
Access Removal
Storage access is granted for the life of the document and as long as the document's frame is attached to the DOM. This means:
In addition, the browser may decide to remove access on a timeout basis or on some dedicated user action such as switching cookie policy.
WebKit Specifics
WebKit's implementation of Storage Access API will be available in Safari Technology Preview soon and on by default. It only covers cookie access, i.e. no other storage mechanisms and the partitioning of them is affected by a call to requestStorageAccess() at this point.
The text was updated successfully, but these errors were encountered: