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

Let first-parties list third-parties which can request storage access without further requirements #51

Closed
mpirog-hw opened this issue Jun 16, 2020 · 14 comments
Assignees

Comments

@mpirog-hw
Copy link

mpirog-hw commented Jun 16, 2020

Prior to ITP 2.1, third-party websites had access to partitioned cookie storage when navigated to within an iframe.

With removal of partitioned storage and the introduction of ITP 2.3, it becomes necessary for third-party websites to request storage access from the user via the Storage Access API. However, if the user has not interacted with the third-party in a first-party context within the last 30 days, the API preemptively returns false before the user is prompted.

This creates a permission deadlock for websites that operate in an embed-only context and which depend on a session or authentication cookie for operation.

The workflow that appears to be necessary to circumvent this deadlock would require an artificial approach to: first flag the third-party as a first-party, then request storage access in third-party context.

Example scenario: website.example is a first-party website that displays a third-party website, information.exmaple, in an iframe. information.example needs to store a session or authentication cookie.

  1. user navigates to website.example which needs to render information.example in an iframe
  2. website.example redirects to information.example?returnUrl=website.example
  3. information.example displays some element and requests that the user interacts/gestures
  4. on user interaction, WebKit flags the domain as a 'domain having had first-party interaction within 30 days'
  5. information.example navigates to the returnUrl supplied by website.example
  6. website.example presents the iframe
  7. when the user interacts with the contents of the iframe, information.example requests storage access via the Storage Access API
  8. the Storage Access API request results in a user prompt with an ominous message asking to grant permission to information.example
  9. if allowed, information.example can store a session and/or authentication cookie and continue

This is a bad user experience by any measure and introduces a requirement for cooperation between the first-party and third-party that is unrealistic in many scenarios.

A solution to this would be to allow the first-party to whitelist the third-party domain when it defines the iframe, similar to <iframe>'s sandbox extension and the allow-storage-access-by-user-activation attribute.

For example: <iframe sandbox="allow-whitelisted-storage-access"></iframe>.

@johnwilander
Copy link
Collaborator

johnwilander commented Jun 16, 2020

Hi! Thanks for filing.

Prior to ITP 2.1, third-party websites had access to partitioned storage when navigated to within an iframe.

With removal of partitioned storage

I'd rather not discuss too many ITP-specific things here but only partitioned cookies were removed in 2019. Partitioned LocalStorage remains and has been there since 2013 in the case of WebKit.

and the introduction of ITP 2.3, it becomes necessary for third-party websites to request storage access from the user via the Storage Access API. However, if the user has not interacted with the third-party in a first-party context within the last 30 days, the request is preemptively rejected before the user is prompted.

This creates a permission deadlock for websites that operate in an embed-only context and which depend on a session or authentication cookie for operation.

This is not true, unless I'm missing some point. A rejected request where the user was never prompted will preserve the user click/tap which allows the iframe to open a popup in which they can get user interaction as first party. This is at least WebKit's shipping behavior and the preservation of the click/tap has been discussed in issues here.

The workflow that would be required to circumvent this deadlock would look like this:

  1. user navigates to website.example which needs to render information.example in an iframe
  2. website.example redirects to information.example?returnUrl=website.example
  3. information.example displays an element, asking the user to interact/gesture along with an explanation as to what is happening
  4. on gesture, information.example uses the Storage Access API to prompt the user with an ominous message to grant permission

My understanding of your explanation is that information.example is first party website here. If that is the case, the Storage Access API is neither needed nor usable by them. information.example will have access to its unpartitioned storage by virtue of being first-party.

  1. on successful granting, information.example stores a cookie
  2. information.example redirects navigation to the returnUrl supplied by website.example
  3. website.example presents the iframe

In this case, the information.example iframe will not have access to unpartitioned storage since it has not requested storage access under website.example.

This is a bad user experience by any measure and introduces a requirement for cooperation between the first-party and third-party that is unrealistic in many scenarios.

A solution to this would be to allow the first-party to whitelist the third-party domain when it defines the iframe, similar to <iframe>'s sandbox extension and the allow-storage-access-by-user-activation attribute.

The Storage Access API is geared toward user control, not site control. For the user to have a chance to recognize the requesting third party, it needs to have been to that website as first party.

For example: <iframe sandbox="allow-whitelisted-storage-access"></iframe>.

Please use the terms allow list and block/deny list. Thanks!

@johnwilander johnwilander self-assigned this Jun 16, 2020
@johnwilander johnwilander changed the title Allow first-party to whitelist third-party for storage access Let first-parties list third-parties which can request storage access without further requirements Jun 16, 2020
@mpirog-hw
Copy link
Author

I'd rather not discuss too many ITP-specific things here but only partitioned cookies were removed in 2019. Partitioned LocalStorage remains and has been there since 2013 in the case of WebKit.

Thanks for the clarification. I've updated the text to reflect this.

In this case, the information.example iframe will not have access to unpartitioned storage since it has not requested storage access under website.example.

You are correct! I had missed a step in my explanation, which has been updated. Unfortunately, the added steps only make the user experience worse.

and the introduction of ITP 2.3, it becomes necessary for third-party websites to request storage access from the user via the Storage Access API. However, if the user has not interacted with the third-party in a first-party context within the last 30 days, the request is preemptively rejected before the user is prompted.
This creates a permission deadlock for websites that operate in an embed-only context and which depend on a session or authentication cookie for operation.

This is not true, unless I'm missing some point. A rejected request where the user was never prompted will preserve the user click/tap which allows the iframe to open a popup in which they can get user interaction as first party. This is at least WebKit's shipping behavior and the preservation of the click/tap has been discussed in issues here.

I am interpreting this to mean that a popup could be presented by the third-party to request user interaction for the purpose of achieving first-party interaction context. If this is correct, is there documentation you could point me to?

The Storage Access API is geared toward user control, not site control. For the user to have a chance to recognize the requesting third party, it needs to have been to that website as first party.

This is the concern. I realize what this is hoping to achieve, but it has consequences for legitimate workflows which I've tried to illustrate here. I also realize that significant improvements to web security can't be achieved without some collateral damage, but I'll challenge labeling it as successful progress if that damage isn't reasonably addressed.

@johnwilander
Copy link
Collaborator

I'd rather not discuss too many ITP-specific things here but only partitioned cookies were removed in 2019. Partitioned LocalStorage remains and has been there since 2013 in the case of WebKit.

Thanks for the clarification. I've updated the text to reflect this.

In this case, the information.example iframe will not have access to unpartitioned storage since it has not requested storage access under website.example.

You are correct! I had missed a step in my explanation, which has been updated. Unfortunately, the added steps only make the user experience worse.

and the introduction of ITP 2.3, it becomes necessary for third-party websites to request storage access from the user via the Storage Access API. However, if the user has not interacted with the third-party in a first-party context within the last 30 days, the request is preemptively rejected before the user is prompted.
This creates a permission deadlock for websites that operate in an embed-only context and which depend on a session or authentication cookie for operation.

This is not true, unless I'm missing some point. A rejected request where the user was never prompted will preserve the user click/tap which allows the iframe to open a popup in which they can get user interaction as first party. This is at least WebKit's shipping behavior and the preservation of the click/tap has been discussed in issues here.

I am interpreting this to mean that a popup could be presented by the third-party to request user interaction for the purpose of achieving first-party interaction context. If this is correct, is there documentation you could point me to?

What kind of documentation are you looking for? Have you read our blog posts on updates to ITP and the Storage Access API? Or are you looking for the conversation we've had here in the standards process?

The Storage Access API is geared toward user control, not site control. For the user to have a chance to recognize the requesting third party, it needs to have been to that website as first party.

This is the concern. I realize what this is hoping to achieve, but it has consequences for legitimate workflows which I've tried to illustrate here. I also realize that significant improvements to web security can't be achieved without some collateral damage, but I'll challenge labeling it as successful progress if that damage isn't reasonably addressed.

What is the concern? That the user gets control over this? Or that the third-party has to "reveal" itself as first-party website?

The Storage Access API is intended for authenticated embeds, and to become authenticated the user has to interact with the embedded site as first party.

Either letting first party sites control what third parties are allowed to do or no controls at all is what lead us to cross-site tracking on the web.

@mpirog-hw
Copy link
Author

What kind of documentation are you looking for? Have you read our blog posts on updates to ITP and the Storage Access API? Or are you looking for the conversation we've had here in the standards process?

I'm looking for a comprehensive list of all of the requirements needed to successfully prompt a Safari user. I did read through the blog posts and found requirements to achieve a prompt with the Storage Access API, but not as it relates to its Safari-specific implementation. Ideally, I'd like to find documentation that indicates best practices for solving scenarios where all of those requirements aren't met on initial user interaction, i.e. embed-only use cases.

What is the concern? That the user gets control over this? Or that the third-party has to "reveal" itself as first-party website?

Both.

User control: User control is not always a positive thing. It makes sense in a web centered on social media and advertisement mechanisms, but branching out into something like healthcare has implications. For example, cognitive science shows us that positive health behavior change can be undermined by introducing complexity. Getting information to patients as quickly and seamlessly as possible is critical.

Third-party reveal: The reveal itself isn't the concern, but rather what it implies in the case of a user who is unaware of the third party and its domain (by design). It's asking the user if they recognize a domain, not to determine whether it is "safe". This tips the scale of usability to the most well known entities, i.e, those with the most effective advertising/exposure. Not all of us engage in advertising or brand recognition to end users.

Either letting first party sites control what third parties are allowed to do or no controls at all is what lead us to cross-site tracking on the web.

I don't see how these security changes eliminate cross-site tracking. It really seems like they just narrow the playing field -- choosing winners and losers. If you have the clout to offer a high-exposure solution (e.g. Google, Facebook) on the web that users interact with at least every 30 days and have the recognition such that your domain is identifiable by your average Safari user, you're in. If not, you're out. Safari and this API make this decision, not the user. Even in the case of the user prompt, the prompt's text itself is designed to influence the choice the user makes.

@johnwilander
Copy link
Collaborator

What kind of documentation are you looking for? Have you read our blog posts on updates to ITP and the Storage Access API? Or are you looking for the conversation we've had here in the standards process?

I'm looking for a comprehensive list of all of the requirements needed to successfully prompt a Safari user. I did read through the blog posts and found requirements to achieve a prompt with the Storage Access API, but not as it relates to its Safari-specific implementation. Ideally, I'd like to find documentation that indicates best practices for solving scenarios where all of those requirements aren't met on initial user interaction, i.e. embed-only use cases.

Sure. I've received requests for a how-to guide previously and will consider it.

What is the concern? That the user gets control over this? Or that the third-party has to "reveal" itself as first-party website?

Both.

User control: User control is not always a positive thing. It makes sense in a web centered on social media and advertisement mechanisms, but branching out into something like healthcare has implications. For example, cognitive science shows us that positive health behavior change can be undermined by introducing complexity. Getting information to patients as quickly and seamlessly as possible is critical.

I don't see a way for browsers to make that distinction and create exceptions for certain combinations of first- and third-parties based on it.

My perspective is that the browser is the user agent, i.e. it is on the user's side, acting on behalf of the user. In this specific case, protecting the user from being invisibly and automatically identified by a third party.

Third-party reveal: The reveal itself isn't the concern, but rather what it implies in the case of a user who is unaware of the third party and its domain (by design). It's asking the user if they recognize a domain, not to determine whether it is "safe". This tips the scale of usability to the most well known entities, i.e, those with the most effective advertising/exposure. Not all of us engage in advertising or brand recognition to end users.

This may come down to decisions for individual browser vendors but in the case of WebKit, our tracking prevention policy clearly states "no exceptions," meaning the same rules for all domain names.

Either letting first party sites control what third parties are allowed to do or no controls at all is what lead us to cross-site tracking on the web.

I don't see how these security changes eliminate cross-site tracking. It really seems like they just narrow the playing field -- choosing winners and losers. If you have the clout to offer a high-exposure solution (e.g. Google, Facebook) on the web that users interact with at least every 30 days and have the recognition such that your domain is identifiable by your average Safari user, you're in. If not, you're out. Safari and this API make this decision, not the user. Even in the case of the user prompt, the prompt's text itself is designed to influence the choice the user makes.

Eliminating all cross-site tracking will take time. WebKit is pretty far along the path of doing so and blocking all third-party cookies was an important milestone in that effort.

Giving first parties the ability to relax restrictions on which third parties can request storage access is not under consideration at this point. The only thing I can see working is to use such an allow list to further restrict third parties. However, that can already be achieved through the sandbox directive allow-storage-access-by-user-activation.

@vitaliy-kretsul
Copy link

I just want to add my voice to @openfermentation because the workflow he described is exactly what I am currently experiencing and what concerns me.

This is not true, unless I'm missing some point. A rejected request where the user was never prompted will preserve the user click/tap which allows the iframe to open a popup in which they can get user interaction as first party. This is at least WebKit's shipping behavior and the preservation of the click/tap has been discussed in issues here.

Does this mean that the possible workflow for the user who has not interacted with the third-party in a first-party context would be like this:

  1. user navigates to website.example which needs to render information.example in an iframe
  2. user makes a gesture in information.example subframe to request Storage Access API and gets rejected because he has not interacted with the third-party in a first-party context
  3. considering that rejected request preserve the user click, we can now open a popup window with information.example as first-party
  4. now user have to interact with popup. For example click a button (which may also serve for closing popup window).
  5. then user interacts/gestures with information.example subframe once again to request Storage Access API and this time he gets a prompt asking to grant permission to information.example
  6. if user consent to Storage Access API prompt, then information.example subframe finally can store a session and/or authentication cookie and continue

Basically, this workflow is the same as described by @openfermentation with the only difference that instead of redirecting to third-party domain in order to get interaction as first-party and then redirecting back, we can use a popup window.

Is that workflow correct? Or am I missing something? If that is true then it is obviously doesn't look like a good user experience. Not mentioning we artificially force user to interact with third-party in first-party context.

@vitaliy-kretsul
Copy link

@johnwilander
will really appreciate if you find some time to reply to my previous message. Thank you!

@mandys
Copy link

mandys commented Jul 22, 2020

@vitaliy-kretsul i don't think step 5 above is necessary.
i was able to request storage access on close of popup so that additional step isn't required.
the popup can be an explainer popup on which user can click "agree & proceed" which closes the popup and throws the safari prompt.

@jackfrankland
Copy link

i was able to request storage access on close of popup so that additional step isn't required.
the popup can be an explainer popup on which user can click "agree & proceed" which closes the popup and throws the safari prompt.

Interesting. I assume that you are handling the popup's click event from the context of the iframe's document within the same synchronous call (they share the same origin), and the user action is still valid in the storage access request? I wonder if this is actually intentional or not, or if a check should be made that the target document of the user action matches the one receiving the request?

I've thought about this before in the context of many iframes on the same page (user action in 1 iframe allowing the request to be performed in another of the same origin), but considering all iframes can receive storage access for the life of the top-level document anyway it isn't much of an issue. When it comes to user actions in popups though, perhaps this should be addressed.

@vitaliy-kretsul
Copy link

@mandys and @jackfrankland those are interesting workarounds, thanks for your comments.
Still, I would like to hear first-hand what was the intended workflow.
@johnwilander

@vitaliy-kretsul
Copy link

@vitaliy-kretsul i don't think step 5 above is necessary.
i was able to request storage access on close of popup so that additional step isn't required.
the popup can be an explainer popup on which user can click "agree & proceed" which closes the popup and throws the safari prompt.

@mandys It would be interesting to take a look at how exactly you achieved this. Would you mind sharing some examples? Thank you

@johnwilander
Copy link
Collaborator

johnwilander commented Jul 24, 2020

I just want to add my voice to @openfermentation because the workflow he described is exactly what I am currently experiencing and what concerns me.

This is not true, unless I'm missing some point. A rejected request where the user was never prompted will preserve the user click/tap which allows the iframe to open a popup in which they can get user interaction as first party. This is at least WebKit's shipping behavior and the preservation of the click/tap has been discussed in issues here.

Does this mean that the possible workflow for the user who has not interacted with the third-party in a first-party context would be like this:

  1. user navigates to website.example which needs to render information.example in an iframe
  2. user makes a gesture in information.example subframe to request Storage Access API and gets rejected because he has not interacted with the third-party in a first-party context
  3. considering that rejected request preserve the user click, we can now open a popup window with information.example as first-party
  4. now user have to interact with popup. For example click a button (which may also serve for closing popup window).

In WebKit, and I believe also Gecko/Firefox, interacting with the popup already opens up cookie access for the third-party under the opener page. So at this point you're done.

The second time, the user will have interacted with information.example as first party and so the browser will prompt for storage access.

The third time and onward, the user will have opted in to storage access for information.example under website.example and storage access will be granted automatically without prompt.

  1. then user interacts/gestures with information.example subframe once again to request Storage Access API and this time he gets a prompt asking to grant permission to information.example
  2. if user consent to Storage Access API prompt, then information.example subframe finally can store a session and/or authentication cookie and continue

Basically, this workflow is the same as described by @openfermentation with the only difference that instead of redirecting to third-party domain in order to get interaction as first-party and then redirecting back, we can use a popup window.

Is that workflow correct? Or am I missing something? If that is true then it is obviously doesn't look like a good user experience. Not mentioning we artificially force user to interact with third-party in first-party context.

@johnwilander
Copy link
Collaborator

I'm looking for a comprehensive list of all of the requirements needed to successfully prompt a Safari user. I did read through the blog posts and found requirements to achieve a prompt with the Storage Access API, but not as it relates to its Safari-specific implementation. Ideally, I'd like to find documentation that indicates best practices for solving scenarios where all of those requirements aren't met on initial user interaction, i.e. embed-only use cases.

Sure. I've received requests for a how-to guide previously and will consider it.

Such a how-to guide was published a year ago, Feb 2021. See "How To Use the Storage Access API": https://webkit.org/blog/11545/updates-to-the-storage-access-api/

@johnwilander
Copy link
Collaborator

The best proposal so far to achieve what this issue is asking for is being dicussed in #83, specifically see my detailed proposal in #83 (comment).

Let's continue the conversation there. Thanks!

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

No branches or pull requests

5 participants