Skip to content
This repository has been archived by the owner on Jun 30, 2023. It is now read-only.

CORS Anonymous requests complicates preconnect #32

Closed
pmeenan opened this issue May 5, 2015 · 23 comments
Closed

CORS Anonymous requests complicates preconnect #32

pmeenan opened this issue May 5, 2015 · 23 comments

Comments

@pmeenan
Copy link

pmeenan commented May 5, 2015

I'm running into a few issues in the Chrome implementation that are causing preconnect to not be as effective as we'd like, specifically when it comes to preconnecting for CORS anonymous resources (and fonts in particular).

Specifically, the font-face spec requires that fonts be loaded in "Anonymous" mode and anonymous mode requires clean connections where there is no chance of credentials being shared (cookies, HTTP auth, client certificates).

Unless there is a way to request "Anonymous" mode CORS connections as part of preconnect then CORS fonts will likely not be able to benefit from preconnected connections (at least on Chrome but in a lot of cases other browsers as well).

[crbug: https://code.google.com/p/chromium/issues/detail?id=468005]

@pmeenan
Copy link
Author

pmeenan commented May 5, 2015

Also see: https://www.w3.org/Bugs/Public/show_bug.cgi?id=26556 which is a similar issue being discussed around the fetch spec.

@yoavweiss
Copy link
Contributor

@mcmanus - was this addressed in the Firefox implementation of preconnect? If so, how?

@pmeenan - If I understand correctly, "anonymous mode" also means that the browser cannot resume previous TLS sessions. That's a pretty huge performance handicap for fonts (regardless of preconnect). Do you know the reason for that?

Maybe there's a way to separate the "no cookies, no HTTP auth" requirement from TLS session resumption in the fonts spec or in CORS?

/cc @annevk

@annevk
Copy link
Member

annevk commented May 5, 2015

@yoavweiss they are intentionally separated. Otherwise you could use one channel to attack another.

@annevk
Copy link
Member

annevk commented May 5, 2015

(Fetch is the CORS specification by the way.)

"preconnect" should probably also support crossorigin just like everything else.

@igrigorik
Copy link
Member

Doing some archive digging...

It looks like original intent in the fonts spec was to apply a "same origin only" restriction on font fetches - see earlier spec language, and discussion on style-www that led to current version. However, this language and resulting behavior is inconsistent with CSP, which specifies font-src, which if omitted is set via default-src.. that, in turn, defaults to a * policy.

Doesn't the above create two conflicting requirements? According to CSP cross-origin font fetches are allowed, but according to the font spec they are not. Also, it's not clear to me why font fetches are restricted to same origin whereas style, script, image, etc, are not.. and why they need a separate (other than CSP) mechanism to control this behavior (CORS opt-in). Can we simplify all of this and defer this behavior to CSP? /cc @mikewest

Last but not least, it's not clear to me why the current font spec sets 'omit-credentials' flag on cross-origin requests. I'm guessing this is an optimization to save bytes, but if the side-effect is that we must open new sockets.. this is a costly perf anti-pattern, and one I'd love to revisit.

@mikewest
Copy link
Member

mikewest commented May 5, 2015

CSP does not grant privileges to a page; it only restricts them. That is, it acts in this case as a limit on top of CORS.

I don't have much of an opinion on the fonts spec, but CSP's behavior as an argument to change the CORS requirements seems weak.

@mcmanus
Copy link

mcmanus commented May 6, 2015

bizarrely I ran into this issue while these updates were queued, unread, in my mailbox.

What I discovered was that the firefox preconnect implementation doesn't help font fetches, for the reasons outlined here.

is the suggestion that crossorigin=anonymous on rel=preconnect would open an anonymous channel?

@igrigorik
Copy link
Member

@annevk @mcmanus for my own education, why does "anonymous" require a separate connection? If I'm reading the spec correctly, it sets the "omit credentials": flag... and it's not clear to me why and how this creates a problem that requires a new socket.

Re, adding support for crossorigin=anonymous for preconnect: that seems reasonable. The fact that fonts fall into this bucket is an orthogonal discussion.

CSP does not grant privileges to a page; it only restricts them. That is, it acts in this case as a limit on top of CORS.

Ah, right.. I guess CSP controls whether the request is made, and CORS allows origin server to control which pages may use the response. Disregard my earlier comment about "deferring to CSP".

That said, I'm still wondering why font-fetches have the anonymous flag on them. If this is an optimization to save bytes, then its backfiring.. e.g. we can't use HTTP/2 connection coalescing and get a perf-hit by requiring a separate socket with a full round of TCP+TLS handshakes.

@mcmanus
Copy link

mcmanus commented May 6, 2015

It seems odd to me too that fonts require anonymous.. but that's a very lay opinion.

I'll let annevk comment on whether anon and non-anon transactions require partitioned sockets, but there isn't much anonymity involved in practice if you hold back credentials on one request but then send them a few bytes later on the same stream.

There are specific problems with authenticated channels such as TLS client certs and NTLM. Its possible those could be made the edge case rather than the base case.

@annevk
Copy link
Member

annevk commented May 6, 2015

[T]here isn't much anonymity involved in practice if you hold back credentials on one request but then send them a few bytes later on the same stream.

This is the reason why credentials mode set to "cors" or "omit" works the way it does.

The reason fonts only support credentials mode set to "cors" is partially because the CSS WG makes case-by-case decisions on what to do for cross-origin fetches rather than properly integrating with Fetch as they should and because not sending credentials makes usage of CORS easier (you can use *). At some point CSS will support the full flurry of settings.

Note that this does not just affect fonts. If you fetch images using <img crossorigin=anonymous> you would want rel=preconnect crossorigin=anonymous too.

@yoavweiss
Copy link
Contributor

From this thread it seems like we can agree to add a crossorigin attribute for rel=preconnect (as well as for preload and prefetch).

Also, I think we need to find a way to relax the anonymous requirement on fonts, at least to a point where we can reuse/resume TLS connections.

@annevk - can you elaborate on "using one channel to attack the other"? If I understand correctly the thought behind fonts not enabled cross-origin was to limit cross-origin leakage (e.g. exposing user login, etc). Is that correct? If so, how can TLS session resumption leak cross-origin data to the current page?

Or maybe we should open a separate thread for that... What would be the best place for that? Fetch? Or the CSSWG?

@annevk
Copy link
Member

annevk commented May 6, 2015

If all the connections to these servers are anonymous (for fonts), how is this a performance problem?

If there are existing connections to these servers from the user on site A, "maliciously crafted" font fetches from site B could maybe get hold of some state or perform actions on behalf of the user (see confused deputy). That's why "non-anonymous" CORS is a little harder (that it's not possible at all for fonts is largely due to the CSS WG not integrating with Fetch, they need to prioritize that as they see fit).

@yoavweiss
Copy link
Contributor

If all the connections to these servers are anonymous (for fonts), how is this a performance problem?

I may be wrong here, but it's my understanding that anonymous TLS connections cannot resume a past session. If that's not the case, then there's no performance issue.
But if it is, it means that establishing an anonymous TLS connection takes longer than a non-anonymous TLS connection, assuming the user have visited the server in the past.

If there are existing connections to these servers from the user on site A, "maliciously crafted" font fetches from site B could maybe get hold of some state or perform actions on behalf of the user (see confused deputy). That's why "non-anonymous" CORS is a little harder (that it's not possible at all for fonts is largely due to the CSS WG not integrating with Fetch, they need to prioritize that as they see fit).

Oh, so the "anonymous" part is not there to protect site B's users from leaking cross-origin data to site A, but the other way around?
Are there examples available of such attacks? And how are fonts different in that aspect than images?

@annevk
Copy link
Member

annevk commented May 6, 2015

I may be wrong here, but it's my understanding that anonymous TLS connections cannot resume a past session.

It's not an "anonymous" TLS connection. It's just a different group from the one with credentials. What is your understanding based on?

And how are fonts different in that aspect than images?

Images fetched with <img crossorigin=anonymous> have the same behavior as fonts. It's just that images also have a "no-cors" mode which fonts do not have because the foundries were uncomfortable with that (not having some means of control) and because "no-cors" is just generally bad security practice from the pre-SOP days.

@yoavweiss
Copy link
Contributor

My understanding is based on this Fetch bug, and "Don't share SSL session caches between the requests". Is that limitation only cross-pool (so that connections in the anonymous pool can reuse past "anonymous" sessions)?

@annevk
Copy link
Member

annevk commented May 6, 2015

Did you read e.g. comment 3 point 1?

Fetch has this under HTTP network fetch:

HTTP requests should be grouped based on the credentials flag. HTTP requests with the credentials flag set should not share anything about the connection or TLS particulars (such as session identifiers) with HTTP requests that have the credentials flag unset. In other words, ambient authority should not leak across this grouping.

@yoavweiss
Copy link
Contributor

OK, thanks! Not an issue then.

@mcmanus
Copy link

mcmanus commented May 6, 2015

oh its still an issue - a site cannot mux and prioritize all its subresources together in h2 if it uses fonts.That's bad perf.

Is there another justification beyond "you can use * to make cors easier" ? If not, sounds like it should be fixed.

@annevk
Copy link
Member

annevk commented May 6, 2015

@mcmanus you have to get more specific. If subresources are same-origin this does not apply. If subresources come from a CDN a site could use crossorigin=anonymous for all of them and let them mux.

Fonts use CORS, just like e.g. JSON does. For CORS (when actually cross-origin) you have "two" modes. Credentialed and not credentialed. None of that will change anytime soon. Fonts maybe need a way to opt into a credentialed way of fetching, but most font providers don't offer support for that as far as I know, so I'm not sure it matters.

@igrigorik
Copy link
Member

The reason fonts only support credentials mode set to "cors" is partially because the CSS WG makes case-by-case decisions on what to do for cross-origin fetches rather than properly integrating with Fetch as they should and because not sending credentials makes usage of CORS easier (you can use *). At some point CSS will support the full flurry of settings.

@annevk what would a "proper integration with Fetch" look like for the fonts spec?

If all the connections to these servers are anonymous (for fonts), how is this a performance problem?

As Patrick mentioned, It means that for cross-origin fetches (e.g. a CDN) you'd end up opening multiple sockets, which is costly for the client and server (handshakes, crypto, etc) and also breaks H2 mux and prioritization. Punting this to developers by asking them to apply "crossorigin=anonymous" is a pretty big gotcha and a major pain -- as exemplified by this very thread; I'm willing to bet that very few developers are aware of this gotcha.

Also, the crossorigin requirement breaks HTTP/2 connection coalescing.. Today, to get the best performance out of HTTP/1 and HTTP/2, I can put some of my assets on a subdomain (i.e. "domain sharding"), and if the origin and subdomain are covered by the same cert, and resolve to same IP, then the HTTP/2 client will automatically re-use the established socket, whereas H1 client will open the extra socket. This is, by far, the simplest and best way to get the best performance out of both protocols.. except, it breaks for fonts, since we're forced to open a new socket regardless.


To recap the thread so far:

  1. I think we're all in agreement that crossorigin support makes sense for preconnect, prefetch, preload. That said, link already defines crossorigin, so technically... everything we need is already there. Do we need anything additional in the RH and Preload specs? I guess I can add a note + example highlighting this.
  2. As a separate and non-blocking issue, it's probably worth kicking off a thread on style-www to revisit the fonts+crossorigin requirement.

Anything else I'm forgetting?

@annevk
Copy link
Member

annevk commented May 7, 2015

Proper integration with Fetch would mean that 1) CSS starts defining fetching resources in a more principled way by actually writing down how it works and 2) CSS could then add support for features Fetch has such as url("http://other-origin/font" credentials=include)" or some such. (Which would require more complex CORS by the CDN but would not defeat mux.)

@annevk
Copy link
Member

annevk commented May 7, 2015

Note also that e.g. SRI also advocates crossorigin=anonymous. So maybe instead we need to figure something out at the protocol level for these mutually distrusting requests to still share some stuff.

@igrigorik
Copy link
Member

@annevk @mcmanus @pmeenan @yoavweiss added crossorigin to spec, ptal: #33

This issue was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants