-
Notifications
You must be signed in to change notification settings - Fork 28
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
Active or passive storage access after explicit user opt-in #2
Comments
When Edge has been looking at this API the decision to persist explicit access across page loads seemed beneficial to unblock embedded content not within an iframe during subsequent navigations as well as improve the user experience when navigating within the same top level site. This may also tie in #3 as unblocking embedded content outside of an iframe would also imply that any grants are scoped to the page not the individual frame. |
Hi!
Do you have concrete examples of this benefit? I understand that third-party content that expects to have cookie access "works better" if it has cookie access but I'm looking for concrete user benefits. Any thoughts on the passive tracking I mention? That was a key thing in our original thinking — the user should be able to load a new webpage and not be identified cross-site unless they engage with content from that cross-site provider.
Let's discuss that part in the dedicated issue since at least for us they are very different. Thanks! |
Hopefully this is more concrete :). One of the key aspects we looked at for this difference was if a user is on blog.example that has that embedded social.example content. If the content isn't fully functional because social.example doesn't have access to storage it will present differently; perhaps show them as not logged in or able to comment/view later. The content can be unblocked by interacting with social.example, requestStorageAccess() is called and the content now "works" from the perspective of the user. Now they reload blog.example or perform a navigation within the domain and there is the same or more content from social.example (perhaps even a tab reload or favourite navigation). If they are now signed out and the content no longer works it is a sub-optimal experience. Showing intent to use the content is great, key even, but this helps balance the impact so that the user can be in control of what they want to access but also not feel like things are broken or the site/browser is "forgetting" them and they have to "sign in, everytime".
I think a balance is required here. Once the user has granted access to the third party content they can be tracked by that entity in relation to the top level site. Does the third party get any more or meaningful information upon a refresh of the page vs the inconvenience of the user who expected the content to still be present/working? Trying to identify that boundary where the intended interaction ends seems to be key here and engagement with blog.example and/or social.example would be a good indicator. Perhaps this also comes down to the scope of the grants. I believe Firefox has the notion of ephemeral grants as well which for the most part is what are dealt with. These only last 24h or the browser session vs the more permanent 30d grants. This would decrease the scope of how long social.example has access to storage when loaded on blog.example while also increasing the users experience. For the longer grants I agree we want to be cautious here. An unfortunate scenario would be someone going to blog.example during one session, granting social.example access, then 25d later re-visiting it and having content allowed. This is a smaller set of cases but an important one. One thing we've been looking at is to potentially tie the extended grants to site-engagement of top level site, blog.example (or potentially even the embedded content social.example). Potentially the logic could be something along the lines of "If explicit access to storage was previously granted via requestStorageAccess(), is still valid (time limit), and the user has recently visited/interacted with the top level page then grant on load". |
Our motivation for implementing the long-lived permission in Firefox was webcompat, ease of user experience for long-lived third-party integrations, and a question of whether we can hope to prevent long-lived passive tracking after the first time access is granted. Ultimately we'll need to decide whether we want to support passive third-party integrations. If so we'll also need to accept the risk of tracking. If not, we'll have to enforce quite a few constraints to provide meaningful protection against long-lived passive tracking, and it's not clear to me that such constraints can be enforced without severely limiting third-party integrations. The "sign in everytime" example in #2 (comment) was also a concern for us. But we encountered login flows that were completely broken if third-party storage access was removed on navigation. Consider the case where example.com embeds a "Login with Social Provider" button from social.example. The user clicks the login button, social.example requests storage access and access is granted, the user approves the login on social.examples site via a popup, and the popup sends back an auth token. In practice many sites will complete the login procedure immediately, but we observed some sites that would redirect after social.example's popup was closed. Those sites expected to be able to access social.example's API on future navigations. Removing storage access after navigation would cause the account setup procedure to break, leading to redirect loops or leaving profiles in a wonky state. IIRC Login with Facebook on IMDB was an example at the time (not sure if it still is). We could consider telling sites that such an integration is no longer supported. This means that every time the site wants to interact with the third party's API the user will first need to click on an embedded iframe from the third party so the party can request storage access. Passive third-party integrations would be completely broken or require the site to constantly annoy the user (e.g., "click here to sync state with third party"). Let's say that we're comfortable killing such integrations and choose to require third parties to re-ask for storage access upon every new page visit. We want to be sure we are meaningfully protecting the user. As discussed in #3 (comment) many trackers already have first-party script access. So social.example requests storage access one time on example.com, access is granted, and they postMessage back their tracking identifier and have their script store it in first-party storage. They never need to ask for storage access again and can continue to passively track the user until first-party storage is cleared. We could further defend against this by imposing restrictions on third-party scripts embedded in the first-party context (we have some ideas on how to do this). This is a hard problem to get right, but let's say we do. Are we sure that we can both support meaningful third-party integrations and prevent long-term passive tracking? Third-party integrations are almost certainly going to need share data with the main context of the page for benign reasons, so preventing that seem limiting. I could also imagine periodically clearing first-party storage when we detect such data sharing across contexts, but again that is will likely be quite limiting as benign sharing is common. On a separate note, we are concerned that our long-lived permission is vulnerable to the types of attacks explored in this paper and are currently thinking through the practical implications. |
At Coral, we're attempting to work around issues posed by recent changes in Safari, namely the blocking of all third party cookies by default. The issue raised in #2 (comment) mirrors our currently situation directly. We have explored the If anyone from this group would like any input from a third party social comment provider (https://github.com/coralproject/talk) feel free to reach out to us! |
Hi! In what way does per-page access stop your commenting service from working? I assume the user has to engage with the commenting widget to comment, at which point requestStorageAccess() can be called. |
Once a user has interacted with the widget by logging in to comment, a top level navigation causes the problem. Because storage access is revoked, we cannot show the user that they are still "logged in" when they get to the new page because we need to request storage access again. To the user, this appears as showing the interface "logged out" and requiring them to click "Sign in" again even though they just signed in before. Imagine the user has logged in, and chooses to view a comment on another story, which causes a navigation to occur. Instead of being able to react/comment immediately, they now have to click "Sign in" first before we can even determine if the user is already signed in. |
Yeah, we're storing a top-level session cookie to workaround this problem. So that once you "log in" inside of the iframe, we store that state on top-level origin instead of on the third-party iframe origin. Then if you refresh/navigate we use the top-level login state instead of using the third-party state. |
This is not the case, at least not in WebKit’s implementation. When a page is loaded, the third-party doesn’t know if the user is logged in or not. That does not mean it has to show “Sign In.” Instead it can show its commenting field and as soon as the user taps/clicks it, document.requestStorageAccess() is called. From that point four things can happen:
|
Maybe this is related to our current UI implementation, but this still doesn't solve the issue at hand. Our current implementation shows a "Signed in as {{ username }}" along with automatically hiding users that the logged in user has "ignored". We also present the "Respected" badges on comments that the current user has already clicked "Respect". The user might navigate, or refresh, just to see the interaction they left being wiped away, driving some user confusion. Without being granted access to the storage after a top level navigation, we cannot present the user with an experience that shows that the user is still signed in. This is our particular case, and maybe that's just a problem for us to solve. I expect however that it is more common than you think that if a user has granted access before (and signed in), after a navigation, the inability to display a logged in state would be detrimental to the user experience. |
I wonder if scenarios like @wyattjoh's will encourage third parties to store more data in the first party. I would hope that it wouldn't get to the point that implementations stored auth tokens, but I can see user preferences and maybe more personal information like a username/email address getting stored, for the sake of a nicer UX. This would be a privacy issue itself of course, as it opens the data up to other parties. |
I think this comes down to old world view vs new world view. The "Show the Sign In button when we have zero cookies" UI was most probably built under the assumption that if the user is logged in, the third-party iframe will know because third-parties have access to cookies. If the assumption instead is that third-parties don't have access to cookies, one would have to build the iframe's UI accordingly, i.e. "We won't know whether or not the user is logged in until they interact with our iframe." Even if storage access were to be persisted over some period of time, say an hour, or for some scope like the life time of the tab, the iframe would still end up in this situation over and over. No cookies, what to show? We've discussed this as part of WebKit's IsLoggedIn proposal:
However, this opens up for both fingerprinting and even a super cookie built with a navigator.isLoggedIn() bit vector similar to HSTS super cookies. |
@fastest963 would you mind to elaborate on why you use a top-level cookie instead of partitioned third-party DOM storage (which, as I understand it, isn't blocked in Safari even when storage access has not been granted)? It seems cleaner/safer to use the partitioned storage since it won't be accessible to other scripts in the first-party context. I'm wondering if there are other considerations I'm not seeing.
This is exactly my concern. We want less third-party scripts embedded into the main context of the page, and less third parties using first-party storage. There's a real risk of incentivizing that if we go with short-lived storage. And for what benefit? Like I discussed in #2 (comment) a motivated third party can continue to track users after their storage access grant has expired. @johnwilander the only way I see short-lived access providing a privacy benefit is if we have future plans to make all storage less permanent (first-party and partitioned third-party). I know Safari has reduced script-writable storage down to 7 days under certain conditions, but this still means trackers can use this storage to passively track users for 7 days after receiving a short-lived storage access grant. Thus, it seems like extending the lifetime of a storage access grant to match the lifetime of the storage locations that can otherwise be used to trivially circumvent the short requestStorageAccess lifetime provides both the same level of protection and a much nicer UX for legit embedded applications. |
Our product provides a way for publishers to add subscriptions to their site with just a script tag. When a visitor to first-party does not have a subscription we would show a paywall with a button to subscribe via iframe (or popup). In that third-party context we call Ideally we could use partitioned storage so other top-level scripts wouldn't have access to our cookie but I'm not sure how that would work. We would always need to make some sort of "stub" iframe so we can get access to the partitioned storage. Additionally, if the third-party iframe was granted storage access then we'd lose access to the partitioned storage so after they subscribe I'm not sure how we'd store something in the partitioned storage for later use.
I agree with this statement but it's not just a problem with the lifetime of the storage. |
This was absolutely considered back when we decided to scope granted access to the lifetime of the requesting iframe (as long as it stays same-site). There are two conflicting goals here. One is that the user is engaging with a specific piece of embedded third-party content, like a video or a commenting widget from social media, and granting that content access to cross-site identifiers. That grant does not imply that the user now wants the video or social media provider to re-identify them on all pages from this website for one hour, one day, or the life time of the tab. Such re-identifying is what we sometimes refer to as "passive cross-site tracking" — the user just loads a new webpage and a third-party identifies them. We want to get rid of all passive cross-site tracking and put the user in control and therefore implemented the storage access scope accordingly. The other one involves the site owner giving the embedded third-party further powers over their website, such as script running in the first party context. In such a case, the third-party can migrate a user identity into the first-party context and achieve passive cross-site tracking across page loads, tabs, and browser restarts. That is an existing problem, not tied to the Storage Access API. The conflict is between explicitly allowing passive cross-site tracking through the Storage Access API on the one hand, and incentivizing more third-party scripts in the first party context + more cross-site identities in first party storage on the other. They are different in nature. The first one is about designing a new API and meeting user expectations (a positive, potentially naive world view). The second one is about looking reality in the eye and not incentivizing something bad (a negative, potentially defeatist world view). It's a tough nut to crack. Maybe the prompt for storage access needs to offer three things: Don't allow, Allow for this page, Allow for this browsing session. Of course formulated by someone with UI skills. |
A number of our customers, and their customers, have been negatively affected with the release of the latest version of Safari. After reading through this thread, I wanted to highlight the issues we're seeing, make the case that the current implementation is too restrictive, and I would argue, causes harm to "the independent web". We (Tula Software) are a software application that yoga studios use to run their businesses. We handle class registrations and bookings, payments, and general account management for a studio's students. One of our key principles is to not get in between our customers and their customers. We are not a marketplace, nor do we ever want to become a marketplace. We want to help independent yoga studio owners maintain their brands, maintain the relationship with their customers, all while providing them with access to the most modern internet tools available. One of the primary ways we do this is with widgets, which our customers install on their websites. They embed calendar, payment form and student account widgets, each into an individual page on their sites. This provides their students with an app-like experience of being logged in when registering for class, checking account information, making payments, etc. The latest updates break all of this core functionality. Reading Data Is User Interaction Reading data is user interaction, and the current implementation does not take this reality into account. On the calendar where people register, we display the number of credits remaining on their accounts. This is useful and valuable information before taking the registration action, when you're thinking about what classes to register for for the week ahead. Likewise, if I'm on a yoga studio website, and I visit the "my account" page, I expect to see my account information, which will contain my past attendances, past purchases, and upcoming registrations, especially if I just previously logged in on the calendar page. I suppose when reading data is the way the user is interacting with the application, one option is to regularly disrupt the end user's experience, and ask them to press a "load my account" button or similar action. But this creates a situation where we cannot create for our merchants an experience that is as good as fully logged in all the time marketplace experience. As an example, imagine if every time you went to book an airbnb, you had to press a "load my account" button on any page where you wanted to see your payment information, view your purchase history, view your booking history, or read through your message thread with a host. This is the situation the latest version of safari creates for our customer's students. Ultimately, the problem is that the latest updates give large marketplaces a competitive User Experience/User Interface advantage over platforms like ours that help independent businesses thrive, in an environment where big tech is already trying to commoditize them as much as possible. I appreciate the work you are doing, and am grateful for the opportunity to comment about this. Thank you. |
Thanks for your comments! We appreciate hearing about more use cases. It is always useful to keep both good and bad use of technical capabilities in mind. While looking at a single website case, it may seem like users obviously want a particular third-party to have access to storage. But things become very different if you consider all the websites that use this third-party and were to present users with the fact that this third-party can follow them for instance when they are comparing competing businesses, and leverage that information to sway them in a particular direction, rig pricing, or deduce things about their lives (Are they moving since this is a new location they're looking at? Have they gotten a raise given the higher price of this new service they're looking at? Have they become parents given that the new place has a child care service?). For a specific first party website, the issue tracked here is whether or not to extend the storage access for a third-party beyond the lifetime of the iframe that was granted storage access. I think we will land in some optionality for browsers here but the closer browsers can get to each other, the easier for developers. In your use case, what would be the minimal reasonable scope to resolve your issue? In various discussions, these options have been mentioned:
|
I agree and fully understand, and finding balance is important indeed. Currently, the implementation suggests there is no such thing as a trusted third party, and that no third party can be trusted. I do not believe this is the case in the real world.
Thanks for asking!
Appreciate the dialog very much, thanks again. |
The Storage Access API is about establishing trust, for some definition of trust. The prompt asks the user and the user gets to decide if they grant the third-party storage access. However, in the case of browsers blocking third-party storage access by default, there is no implicit trust in third parties.
Just so that I understand, are you in this broken state after you've made changes in light of third-party cookie blocking or is it broken because of the old assumption that you would always have third-party cookie access? I.e. have you adopted the Storage Access API and designed the UI for it or is that yet to be done?
Would three options in the prompt work for your customers' users do you think? Kind of "Don't Allow," "Allow on this page," and "Allow for one day." |
All 3 of those options only grants access to the combination of top-level+third-party, correct? Or does Rather than |
Bringing back a suggestion I made in the other thread a while ago: #4 (comment). To take it a little further, if:
then a third party can use DOM storage to store UI / state data (making the experience nicer on subsequent loads), avoiding pollution on the first party. A user action will always be required per iframe for authenticated sessions to be resumed. Would relaxing access to only partitioned DOM storage give trackers a reasonably better chance of tracking someone? This matches the current behaviour in Webkit I believe. |
We are in the broken state because of the old assumption that we would have third party access. Also, all efforts to update the UI to take into account the "new world" all lead to a sub-optimal, non-competitive user experience as previously outlined.
If these prompts were to become common and known behavior for internet users, yes. |
@awicklander Hi, I don't mean this as a criticism, but hopefully as the start of a constructive conversation, but:
I don't think this is accurate. Shopify is also not a marketplace, they're a platform for independent businesses just like you, but they don't have this problem, do they? I think the issue you're running into is related to a detail of your implementation. Not saying it's your fault, and I'm sorry this change broke your assumptions and creates a bunch of work for you, but it fixes an important privacy bug so I think it's here to stay. It sounds like you allow your customers to embed your widgets in static sites? Then it sounds like you have three options:
Note that all of these will have the effect that a login session on one of your customer's sites will no longer translate to also being logged in on another customer's sites, because the whole point of all of this is for someone logged in on one of your customer's sites to be anonymous the first time they visit a different site. That doesn't sound like a problem for your use case though? (I actually don't even use Safari, I use Chrome with third-party cookies blocked as my main browser, so your customers' sites are probably already broken for me. Please fix them, for people like me :) .) |
I think this represents the concern quite well that developers may choose to risk security to overcome limitations.
In a lot of situations it is unrealistic due to the development cost and infosec required, and the nature of the embed. Even if the service were an integral part of the site, it is much more realistic that sites will be able to integrate server-side with Shopify, than it is a relatively less-known business with less reach, so the point about competitiveness is a valid one in my view. |
You really think this change makes a difference? You think people weren't already loading scripts from third-party sources, without subresource integrity, and instead were carefully segregating third-party widgets into iframes? (And I did suggest staying with in the iframe and using partitioned storage, which I believe is still allowed inside hidden iframes, no user gesture required.)
A CNAME is really that onerous?
I don't see the relevance. Isn't it being easy to Shopify a counterexample, because Shopify also isn't a marketplace, it powers independent businesses? And why does being less-known or anything about Tula require them to be inherently harder to integrate-with than Shopify? |
We didn't get to discuss this during the meeting. If a browser only does active granting then it would be nice to see some resolution to #8. If you operate a widget that requires login to be functional, you might want to show an action button (Comment) if you know they won't see a dialog but if they will need to see a browser prompt in order to grant storage you might show something more informative (Login to comment) since it's their first time. The current "solution" presented in the other issue is that it should depend on isLoggedIn to know but it's not clear how that interacts with storage access and if/when that will be implemented/standardized. |
It seems to me that, if a web developer follows the well-lit path (call Maybe we can resolve this as-is, or maybe we should add some prose explaining there may be implementation differences here, but that they don't matter too much? |
I talked about this with John and Tess and we agreed that we will mention in the spec that there may be implementation differences in how the user agent may choose to use the storage access map to decide whether a frame will have access to first-party storage and/or cookies. It may choose to always require a requestStorageAccess call or give access on load based on the existing entry in the storage access map. For this reason it's important that developers use This change will be made when updating the storage section as part of #31. I am hence (finally) closing this issue, thank you everyone. |
The original issue was discussing changes to Safari's implementation. John brought up potentially giving the user multiple options, "not now", "only once", "for a day", or something similar to address the passive vs active issue. I don't think the If I'm understanding Safari's implementation correctly, |
Right, I agree, and this is why Firefox differs in behavior here, but what I'm saying is that as editors we've decided that this isn't really a question for the spec and rather something that we will leave to individual browsers. In #31 we will add wording to that effect. |
I feel the spec should be a guiding principle for browsers to implement something which is consistent and makes app developer's life easier. I concur what @jameshartig pointed out above. We are an embedded SaaS analytics application and for us it is impossible to work when 3rd party cookie access is blocked. It will be great if the spec at least laid out the use cases which are affected by this change, so that the browser implementers can make an informed choice. |
Mozilla's documentation on differences between Safari's and Firefox's implementation covers the difference explained below.
In this case, we assume that the user has explicitly opted in to storage access for third-party social.example under first-party blog.example.
Safari: iframes from social.example under blog.example always need to get user interaction and call document.requestStorageAccess() on that interaction to get cookie access. This means a mere page load of blog.example with an iframe from social.example does not grant the social.example iframe storage access.
Firefox: iframes from social.example under blog.example do not need to get user interaction or call document.requestStorageAccess() to get cookie access for 30 days after the explicit user opt-in. This means a mere page load of blog.example with an iframe from social.example grants the social.example iframe storage access.
Safari is unlikely to allow what we refer to as "passive tracking" and we think user interaction with the authenticated embed should be required for storage access. Hence the title of this issue "Active or passive storage access."
However, we're open to making this behavior optional. To reach consensus on how to spec this, it would be helpful to get Mozilla's use cases and motivations.
The text was updated successfully, but these errors were encountered: