WICG / view-transitions

https://drafts.csswg.org/css-view-transitions-1/
Other
803 stars 51 forks source link

Document behavior about COOP, and about navigation redirects. #200

Open ArthurSonzogni opened 1 year ago

ArthurSonzogni commented 1 year ago

During the web platform security review: @camillelamy & @arturjanc were wondering if there was some security consideration written about:

In both cases, after thinking about it for a while, I personally don't see any strong evidence any of this can be used by an attacker. Maybe @arturjanc had some ideas (?)

anyway, it would be nice to add some notes on the types of attacks being considered with regards to COOP and redirects, and explain why we think the currently defined behavior looks safe.

jakearchibald commented 1 year ago

The potential attack would be:

  1. Use view transitions to take a representation of an image/iframe from a non-isolated page to an isolated page.
  2. In the isolated page, use high res timers + spectre/melton to read the image data.

For this case, the spec would require that the old view images are stored in another process. That's how the current Chrome implementation works. I think that's enough, right?

  • Redirect: A cross-origin navigation redirecting back to a same-origin one. Potential "Confused deputy attack" kind of issues maybe?

The potential attack would be:

  1. Navigate from //origin-a/page-1 to //origin-b/login.cfm, which may redirect to //origin-a/page-2.
  2. If a transition happens, we know it went straight from //origin-a/page-1 to //origin-a/page-2, leaking the fact a redirect happened, potentially leaking login state.

I believe this is already leaked for navigation in a bunch of ways:

camillelamy commented 1 year ago

The potential attack would be:

  1. Use view transitions to take a representation of an image/iframe from a non-isolated page to an isolated page.
  2. In the isolated page, use high res timers + spectre/melton to read the image data.

For this case, the spec would require that the old view images are stored in another process. That's how the current Chrome implementation works. I think that's enough, right?

  • Redirect: A cross-origin navigation redirecting back to a same-origin one. Potential "Confused deputy attack" kind of issues maybe?

The potential attack would be:

  1. Navigate from //origin-a/page-1 to //origin-b/login.cfm, which may redirect to //origin-a/page-2.
  2. If a transition happens, we know it went straight from //origin-a/page-1 to //origin-a/page-2, leaking the fact a redirect happened, potentially leaking login state.

I believe this is already leaked for navigation in a bunch of ways:

  • Timing: There'll be a large delta between the pagehide of the old page and JS execution starting on the new page depending on whether a redirect happens.
  • Inspection: If the intermediate page performs a non-replacement navigation, this will be visible in history.length and the navigation API. Although this can be hidden with a replacement navigation.
  • Inspection: With a same-BCG top-level window (window.open), an intermediate navigation can be detected by accessing contentDocument and seeing when it becomes unaccessible, and re-accessible.

I think you are thinking of a client redirect. We are concerned about a server redirect. In the server redirect case, there should be no delta between the pagehide of the old page and JS execution starting on the new page. Similarly, there should not be an extra entry in the history and navigation API. Similarly, the page always remains accessible.

jakearchibald commented 1 year ago

I didn't explain properly, or I'm still misunderstanding.

The page knows when it's navigation request is to another origin.

If there's a server redirect back to the same origin, then the page switches from //origin-a/page-1 to //origin-a/page-2, with nothing in between.

If there isn't a server redirect back, the page may still switch from //origin-a/page-1 to some other origin, to //origin-a/page-2.

So, detecting a server redirect means being able tell the difference between the two. View transitions lets you tell this difference, because a transition will happen in the server redirect case, but not in the case with an intermediate page.

The point I was trying to make above is that you can already do that same thing via other means, so I don't think view transitions provide anything new.

camillelamy commented 1 year ago

The issue, as we understand it, is that view transition does not check if there is a cross-origin redirect in the middle. So for example:

On regular pages, there are other ways to know this information (eg. by checking what happens from another window). However, if b.com has COOP, the information is harder to learn as there would be a browsing context group switch in the middle of the navigation. So having view transitions happen despite a COOP browsing context group switch and a cross-origin server redirect in the middle can be problematic.

Finally, I have seen in the design doc that there were planned extensions to first-party sets. This is likely to make the issues worse. IMO, you should cancel the transition when there is a cross-origin redirect in the navigation. If an extension to first-party sets happen, then all URLs in the redirect chain should be part of the same first party set and opt into first party sets transition.

jakearchibald commented 1 year ago

On regular pages, there are other ways to know this information (eg. by checking what happens from another window). However, if b.com has COOP, the information is harder to learn as there would be a browsing context group switch in the middle of the navigation. So having view transitions happen despite a COOP browsing context group switch and a cross-origin server redirect in the middle can be problematic.

Ah, I hadn't realised (or I'd forgotten) that a redirect alone could cause a BCG switch.

It still feels like the timing between the outgoing page's pagehide (stored in session storage) and navigation timing on the incoming page would tell you there was no intermediate page. Which means, if your navigation was to another origin (which you can also detect), then it must have redirected back.

I'm less familiar with the plans around first-party sets. I'll look into those.

camillelamy commented 1 year ago

Right I imagine that you could achieve this with session storage.

Another potential issue to consider is whether a cross-origin page can abuse or confuse the website. For example, let's imagine that a website normally has transitions:

Then when the user is on page A, the page navigates to a cross-origin URL which redirects to page C, and we end up having a transition between page A and page C which might be unexpected. Could that behavior be problematic for developers?

Similarly, should we also take into account the initiator of navigations, or is it ok to have the transitions as long as the page we navigate from and the page we arrive to are same-origin?

jakearchibald commented 1 year ago

Hmm, yeah, that's definitely worth considering.

The plan is to provide an event when we're capturing the old page, by which point we hope to know the destination URL and provide it to the developer https://github.com/WICG/view-transitions/blob/main/explainer.md#script-on-old-document. So they could avoid transitions they're unprepared for.

Similarly, the page which actually performs the transition will be given the URL of the previous page https://github.com/WICG/view-transitions/blob/main/explainer.md#script-on-new-document.

Although, developers may choose to avoid the JS and try to do it all in CSS, which means their transitions will likely need to be more generic.

khushalsagar commented 1 year ago

The plan is to provide an event when we're capturing the old page, by which point we hope to know the destination URL

The current implementation does wait for all redirects to be resolved before dispatching a message to the old renderer process so we know whether the final URL for the navigation is same-origin (and a transition can occur). In terms of transitions between pages with incompatible COOP policies, there are 2 data types that are transferred between the old/new Documents to consider:

should we also take into account the initiator of navigations, or is it ok to have the transitions as long as the page we navigate from and the page we arrive to are same-origin?

I think as long as the old/new Documents are same-origin, transitions between them is reasonable. Consider the case where the user copies a URL to go from A -> C in a tab, it may or may not be a navigation expected by the site. And its fair to let the developer decide a custom transition here. Note that there is already an option in the API to allow sites to decoratively opt-in to transitions here. Currently its for all same-origin navigations but if unexpected same-origin navigations is a common issue, we can add support for allow-list/block-list of same-origin URLs.