w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.36k stars 641 forks source link

[css-view-transitions-2] Support same-site cross-origin view transitions #10364

Open khushalsagar opened 1 month ago

khushalsagar commented 1 month ago

The cross-document spec currently limits transitions to Document in the same-origin. This misses a common use-case of transitions on same-site cross-origin navigations: a.example.com -> b.example.com.

Since there is a security boundary between each origin, and transitions require sending the captured element data from the old Document to the new Document, this can't be done by default. But it should be feasible if both Documents opt-in to transitions from each other.

The above can likely be added to the @view-transition rule using 2 descriptors: from/to. Where the descriptor provides the URLs for Documents which it permits transitions from or to. The default value (same-origin?) would limit to only same-origin URLs. Something like on a.example.com:

/* Applies to all same-origin navigations */
@view-transition {
  navigation: auto;
}

@view-transition {
  navigation: auto;
  from: url-pattern("https://b.example.com/*");
}

The idea of from/to was discussed on https://github.com/w3c/csswg-drafts/issues/8925 and this is a good use-case which needs it.

We can also add a keyword like same-site to opt-in to transitions from/to any same-site URL.

@vmpstr @noamr @bramus @jakearchibald @nt1m

khushalsagar commented 1 month ago

If we're ok with script to start with (since url-pattern will have to be its own addition to css), we can also just start with the same-site keyword. So from/to can take 2 keywords: same-site and same-origin with the default being same-origin. Authors can do per URL filtering using the pageswap event which provides the destination URL.

noamr commented 1 month ago

Note also that NavigationActivation and pageswap have relevant same-origin restrictions that would have to be relaxed for this to work.

khushalsagar commented 1 month ago

Note also that NavigationActivation and pageswap have relevant same-origin restrictions that would have to be relaxed for this to work.

Good point! Can you think of any issues with relaxing the restriction, if the site has a vt opt-in?

SebastianZ commented 1 month ago

How about adding a new Content Security Policy (CSP) directive for this instead? That would make this feature very flexible and even allow to opt into different-site cross-origin view transitions, plus, it's a little faster than defining it in CSS because it's defined within a header and it aligns well with other CSS-related features like font-src.

Sebastian

khushalsagar commented 1 month ago

How about adding a new Content Security Policy (CSP) directive for this instead?

Love it! Especially with the example of font-src you mentioned. We'd likely still want from/to eventually so authors can do transition customization declaratively. But since opt-ing into same-site cross-origin transitions is a security policy, CSP seems like a better place for it.

even allow to opt into different-site cross-origin view transitions

Different-site cross-origin is fundamentally harder to do for multiple other reasons:

This is not to say cross-site is completely infeasible, but it needs a deeper dive into what control we actually want to give to authors vs letting majority of the experience to be defined by the UA.

noamr commented 1 month ago

Note also that NavigationActivation and pageswap have relevant same-origin restrictions that would have to be relaxed for this to work.

Good point! Can you think of any issues with relaxing the restriction, if the site has a vt opt-in?

The vt opt in itself is not enough because you can't read it in the old page before the new page is parsed. CSP is perhaps more suitable because it can be delivered in HTTP headers.

But the main restriction that's going to have to be relaxed is on navigation API session history, as for effective cross-doc navs you need to know where you're going to post-redirects and also where you came from (which might not be the referrer if you're traversing). Currently all of this is same-origin. There are not many things that are same-site protected and it's challenging to get right.

I can't tell if a CSP opt-in is enough for this, it's a good conversation to have with security folks. My point is if we were to do this I would start from history and derive view transitions from that rather than jump straight to CSS.

noamr commented 1 month ago

How about adding a new Content Security Policy (CSP) directive for this instead? That would make this feature very flexible and even allow to opt into different-site cross-origin view transitions, plus, it's a little faster than defining it in CSS because it's defined within a header and it aligns well with other CSS-related features like font-src.

Note that CSP is designed as an opt-out only, meaning any added policy can only be further restricting what precedes it or the default. It's not a good framework for something that's supposed to be restricted by default and relaxed using an opt-in.

khushalsagar commented 1 month ago

My point is if we were to do this I would start from history and derive view transitions from that

That's fair. We might need 2 policies, one to allow same-site URLs to be visible in the navigation API session history and another for view-transition. And the view-transition can't apply without a navigation API opt-in.

Note that CSP is designed as an opt-out only, meaning any added policy can only be further restricting what precedes it or the default. It's not a good framework for something that's supposed to be restricted by default and relaxed using an opt-in.

Can you expand on "designed as an opt-out only"? Since on the surface it looks like a key -> list of URLs, it's not obvious why that list can't be used as an allow list on top of any same-origin URL.

noamr commented 1 month ago

My point is if we were to do this I would start from history and derive view transitions from that

That's fair. We might need 2 policies, one to allow same-site URLs to be visible in the navigation API session history and another for view-transition. And the view-transition can't apply without a navigation API opt-in.

Note that CSP is designed as an opt-out only, meaning any added policy can only be further restricting what precedes it or the default. It's not a good framework for something that's supposed to be restricted by default and relaxed using an opt-in.

Can you expand on "designed as an opt-out only"? Since on the surface it looks like a key -> list of URLs, it's not obvious why that list can't be used as an allow list on top of any same-origin URL.

CSP is a list of policies, each policy with multiple directives. Every policy can only tighten what's before it, not relax it. It's built in a way that a policy injected (eg in a CDN header) can't relax security beyond the current state.

bramus commented 1 month ago

My gut reaction was to have an opt-in through CSS, as not all authors have control over setting the headers.

@view-transition {
  navigation: auto;
  origins: a.example.com, b.example.com; /* Or maybe even `*.example.com`? */
}

I would prefer to explicitly list the origins here, so that in the future – if it ever would become a thing – cross-origin VTs can use the same descriptor to include other sites.

@view-transition {
  navigation: auto;
  origins: *.example.com, *.example.org;
}

(Note: I’m not suggesting to add cross-site support here and now; am merely thinking ahead to make sure the syntax can support that, if needed)

An alternative would be to allow a combination of the values same-origin, cross-origin, same-site, cross-site for the suggested descriptor but in that case:

natechapin commented 3 weeks ago

Note also that NavigationActivation and pageswap have relevant same-origin restrictions that would have to be relaxed for this to work.

Good point! Can you think of any issues with relaxing the restriction, if the site has a vt opt-in?

The vt opt in itself is not enough because you can't read it in the old page before the new page is parsed. CSP is perhaps more suitable because it can be delivered in HTTP headers.

But the main restriction that's going to have to be relaxed is on navigation API session history, as for effective cross-doc navs you need to know where you're going to post-redirects and also where you came from (which might not be the referrer if you're traversing). Currently all of this is same-origin. There are not many things that are same-site protected and it's challenging to get right.

I can't tell if a CSP opt-in is enough for this, it's a good conversation to have with security folks. My point is if we were to do this I would start from history and derive view transitions from that rather than jump straight to CSS.

Do I understand correctly that this would require navigation.activation.from to be populated in the cross-origin-but-same-site case?

I think that's probably doable if both origins consent to it, but it would be important to note that some of the information on navigation.activation.from would be incomplete or unusuable. Most notably, a from.key would be rejected if given to navigation.traverseTo, and from.index would always be -1.

We would also need to think carefully about from.url behaves. Would it be ok for it to be origin-only? Would it break view transitions if it was censored due to referrer policy?

khushalsagar commented 3 weeks ago

Do I understand correctly that this would require navigation.activation.from to be populated in the cross-origin-but-same-site case?

Yes, the Document would need this information to customize the transition.

I think that's probably doable if both origins consent to it, but it would be important to note that some of the information on navigation.activation.from would be incomplete or unusuable. Most notably, a from.key would be rejected if given to navigation.traverseTo, and from.index would always be -1.

Can you expand on this a bit more? My thinking was that an opt-in from 2 same-site cross-origin URLs means we can expose all the information that is provided by the navigation API to same-origin URLs. Is there a reason we shouldn't do that? And specifically about your comment for traverseTo, do you think this opt-in should only provide readonly state but not allow authors to do actions provided by the navigation API..?