Bug 86817 - Downloadable font loads should be subject to CORS
Summary: Downloadable font loads should be subject to CORS
Status: NEW
Alias: None
Product: WebKit
Classification: Unclassified
Component: CSS (show other bugs)
Version: 528+ (Nightly build)
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Myles C. Maxfield
URL:
Keywords: InRadar
: 53435 (view as bug list)
Depends on:
Blocks: 245827 249887
  Show dependency treegraph
 
Reported: 2012-05-17 23:44 PDT by Boris Zbarsky
Modified: 2023-06-23 06:32 PDT (History)
17 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Boris Zbarsky 2012-05-17 23:44:56 PDT
http://dev.w3.org/csswg/css3-fonts/#default-same-origin-restriction says that cross-origin font loads should only be allowed if CORS says so.
Comment 1 Alexey Proskuryakov 2012-05-18 13:00:54 PDT
This sounds much like bug 53435, just for a different spec.

It appears that the same reasons for not doing this would apply here.
Comment 2 Boris Zbarsky 2012-05-18 13:11:42 PDT
It's similar.  The requirement got moved to the fonts spec, out of WOFF, so now it applies to all fonts, not just WOFF fonts.

Again, Gecko and IE are complying with the spec today.  The main effects of WebKit not doing so, as far as I can see, are sites inadvertently violating their font licenses and authors being confused about the proper way to deploy fonts.

If you really do think the spec here should be changed, the right approach is to say so in the relevant standards group, not to try to use market position to subvert the spec by simply not implementing it.
Comment 3 Theresa O'Connor 2012-05-18 15:08:37 PDT
Off-topic; just correcting Boris on this one point:

(In reply to comment #2)
> If you really do think the spec here should be changed, the right approach is to say so in the relevant standards group[...]

We (and others) have. Several people from multiple vendors pushed back on this and advocated for From-Origin for this case, at the joint Fonts/WebApps/WebAppSec meeting at TPAC last year.
Comment 4 Boris Zbarsky 2012-05-19 10:41:39 PDT
> We (and others) have.

Yes, but the working group reached a decision after that, and it's being actively ignored.
Comment 5 youenn fablet 2014-06-19 02:10:31 PDT
Chromium is now aligning with Gecko and IE on this: https://groups.google.com/a/chromium.org/forum/#!topic/blink-dev/sU138vJ_PI0

http://code.google.com/p/chromium/issues/detail?id=286681 contains some interesting information as well (#c7, low compatibility risk...).
Comment 6 Kenji Baheux 2015-07-07 00:30:04 PDT
Sharing an update about % of fonts CORS failures as seen from Chromium:

 Slightly less than a year ago, we started at a 6% failure rate. We are now at 2%.
 
 The trend appears to have flattened.

 Among these failures, there is probably a significant %age that fits in one of the following categories:
  1. long tail / semi-abandoned websites 
  2. legit failures (usage of web fonts without authorization) => WAI


Hope this helps.
Comment 7 Bram Stein 2016-02-11 11:39:20 PST
It would be great if Safari/WebKit starts enforcing the same-origin policy for web fonts. At Adobe Typekit we're currently using referrer header matching to prevent accidental misuse of the fonts we serve to our customers. This is rather heavy handed and doesn't work in some of the use-cases we would like to support (dynamically created iframes, browsers in privacy mode, etc). We would very much like to start using CORS headers on our web fonts instead.

Based on our research (http://stateofwebtype.com/#CORS) Safari is the only major browser that does not enforce the same-origin policy for web fonts. We would appreciate it very much if Safari/WebKit could reconsider their position on this issue.
Comment 8 Alexey Proskuryakov 2016-02-11 13:56:00 PST
The same origin policy is a security policy, not DRM. Is there a web security reason to enforce it for fonts, but not for images, CSS or JavaScript?
Comment 9 Anne van Kesteren 2017-08-15 00:03:12 PDT
I think the security reason is to stop leaks in new features. That images have some cross-origin leaks, doesn't mean we should accept them for fonts.

For the same reason JavaScript modules require CORS (otherwise import URLs end up leaking).
Comment 10 Myles C. Maxfield 2020-01-08 18:25:02 PST
*** Bug 53435 has been marked as a duplicate of this bug. ***
Comment 11 Myles C. Maxfield 2020-01-08 18:25:26 PST
See also the discussion at https://bugs.webkit.org/show_bug.cgi?id=53435
Comment 12 Myles C. Maxfield 2021-09-20 13:54:17 PDT
The last time the WebKit team investigated this was a decade ago, and we didn’t want to do it because of web compatibility. The web landscape has changed dramatically since then - now, WebKit is the only major browser that doesn’t do this.

I think this is worth re-evaluating.
Comment 13 Radar WebKit Bug Importer 2022-07-13 09:57:45 PDT
<rdar://problem/96958310>
Comment 14 Myles C. Maxfield 2022-07-16 20:05:18 PDT
> I think this is worth re-evaluating.

Instead of re-evaluation, I think we should just fix this now.
Comment 15 Alexey Proskuryakov 2022-07-18 14:34:30 PDT
But why "fix" this? Is there any reason at all?
Comment 16 Myles C. Maxfield 2022-07-18 18:43:41 PDT
Yes. We have cases where fonts that work only in safari cause a site to break only in Safari.
Comment 17 Alexey Proskuryakov 2022-07-18 18:55:30 PDT
Are any of those ones that cannot be ignored? This requirement is just so deeply and fundamentally wrong :(
Comment 18 Myles C. Maxfield 2022-07-18 20:31:25 PDT
(In reply to Alexey Proskuryakov from comment #17)
> Are any of those ones that cannot be ignored? This requirement is just so
> deeply and fundamentally wrong :(

It is de-facto part of the web platform by now. The ship has sailed.
Comment 19 Alexey Proskuryakov 2022-07-19 09:18:17 PDT
I don't think that anything has changed since 2011. It was just as much codified in specs and implemented in other browsers back then.
Comment 20 Myles C. Maxfield 2022-09-15 16:32:20 PDT
(In reply to Alexey Proskuryakov from comment #19)
> I don't think that anything has changed since 2011. It was just as much
> codified in specs and implemented in other browsers back then.

Our original argument about not wanting to respect CORS for fonts is that there was too much content that it would break. That is surely no longer true today.
Comment 21 Alexey Proskuryakov 2022-09-15 16:49:27 PDT
The original argument was https://lists.webkit.org/pipermail/webkit-dev/2011-January/015794.html, we didn't want to add pseudo-DRM to the Web. No word on breaking content, which didn't even exist back then.

That was a bad idea, and remains a bad idea.
Comment 22 Myles C. Maxfield 2023-06-14 11:39:21 PDT
(In reply to Alexey Proskuryakov from comment #21)
> The original argument was
> https://lists.webkit.org/pipermail/webkit-dev/2011-January/015794.html, we
> didn't want to add pseudo-DRM to the Web. No word on breaking content, which
> didn't even exist back then.
> 
> That was a bad idea, and remains a bad idea.

Bad idea or not, it is de-facto how the web works.
Comment 23 Myles C. Maxfield 2023-06-14 11:46:15 PDT
I also don’t think it’s OK for WebKit to just make this kind of decision about web behavior. We are part of the relevant standard body. If cors really is a bad idea for fonts, we should bring that up in the standard body, not silently just refuse to implement the spec and silently refuse to be compatible with other browsers. That’s not participating with good faith in the browser community.

I, of course, think we should just implement the same behavior that is implemented literally everywhere else on the web, so I’m not very motivated to actually bring this up in a standards group. So, unless someone is willing to actually do the work to push the web community as a whole toward a new behavior, we should just align with the spec and other browsers.
Comment 24 Myles C. Maxfield 2023-06-14 11:50:28 PDT
(The reason why this is coming up now is that competitive analysis with other browsers is observing us taking different code paths on websites we are measuring because of this behavior difference. This is affecting our measurements.)
Comment 25 Alexey Proskuryakov 2023-06-14 13:10:12 PDT
That's still backwards thinking though. Standards bodies aren't there to force dumb decisions.

> (The reason why this is coming up now is that competitive analysis with other browsers is observing us taking different code paths on websites we are measuring because of this behavior difference. This is affecting our measurements.)

So in other words, websites rely on this WebKit behavior?
Comment 26 Myles C. Maxfield 2023-06-14 14:58:47 PDT
> So in other words, websites rely on this WebKit behavior?

No. They rely on our competitor's behavior.
Comment 27 Alexey Proskuryakov 2023-06-14 17:32:12 PDT
I would need to know more about what you are talking about; too vague to consider as is.
Comment 28 acoulton 2023-06-23 04:06:39 PDT
We've just discovered an example of this behaviour being problematic - attempting to use preloading with cross-domain fonts causes was working fine in all other browsers but causing Safari to render pages with broken fonts on the second or third pageview.

In all other browsers, the actual font request is a CORS request, therefore to add preloading we need to use a crossorigin attribute on the preload as well - eg: <link rel="preload" href="https://..." as="font" type"font/woff2" crossorigin> - so that the preloaded & cached response contains the Access-Control-Allow-Origin etc headers.

But in Safari:

* On the first pageview with an empty cache, devtools shows a single request for the font, initiated by the <link preload tag. It appears the renderer can internally tell that this is pending, so waits for completion as expected. The renderer does not care that the response has CORS headers, and happily renders the font.

* On the second pageview, devtools shows a successful request from cache for the <link preload tag but then a *second* request for the same font URL, initiated by the last tag on the page. It appears the renderer sees that the cached request was a CORS request and therefore sends a second, non-CORS, request. This request comes back with no CORS headers, again the renderer does not care and happily renders the font.

* On the third pageview, devtools shows a single font request initiated by the <link preload tag - but this request fails due to CORS permissions. It appears that the request has used the non-CORS response cached in the previous step. The renderer does not attempt to re-request the font, and the page renders broken with a fallback font.

* On all subsequent pageviews until / unless the cache is cleared, the browser continues to behave the same as the third request, and the page renders broken.


I should clarify that this is despite our server-side CORS policy allowing any origin - the response is always "Access-Control-Allow-Origin: *". 

We don't actually care about enforcing CORS, but we have to use a CORS preload and send CORS response headers to satisfy the (standards-compliant) behaviour of other browsers.

The only workaround we've been able to find is updating our font definitions to include a `.woff`, which is not pre-loaded. This means that:

* Other browsers preload and use the .woff2
* Safari starts off by going through all the steps above to decide that the .woff2 is "broken". However, on the third and subsequent page views it falls back to requesting and loading the .woff. As this hasn't been preloaded, there is no CORS, and so the page renders OK. But this means Safari users are suffering increased bandwidth / latency etc to use the fallback font despite having a perfectly valid version already in cache.
Comment 29 youenn fablet 2023-06-23 05:29:45 PDT
Thanks for the detailed report, this helps a lot.
This is a good example of why we should use CORS for font loads.

> * On the first pageview with an empty cache, devtools shows a single request
> for the font, initiated by the <link preload tag. It appears the renderer
> can internally tell that this is pending, so waits for completion as
> expected. The renderer does not care that the response has CORS headers, and
> happily renders the font.
> 
> * On the second pageview, devtools shows a successful request from cache for
> the <link preload tag but then a *second* request for the same font URL,
> initiated by the last tag on the page. It appears the renderer sees that the
> cached request was a CORS request and therefore sends a second, non-CORS,
> request. This request comes back with no CORS headers, again the renderer
> does not care and happily renders the font.

Preload might be doing a no credentials fetch, while the actual font load might do a credential fetch.
Credentials and ACAO:* are not friends, hence why we might be reloading this resource.

> * On the third pageview, devtools shows a single font request initiated by the <link preload tag - but this request fails due to CORS permissions.

I am surprised here given it seems you always provide ACAO:*.
It would fail due to CORS permissions if we were doing a CORS with credentials fetch, but I assume preload should be using CORS no-credentials.
Maybe there is a bug here (independently of the particular font CORS issue) we could try to further investigate.
@acoulton, is there way for us to reproduce what you are seeing?
Comment 30 acoulton 2023-06-23 06:32:48 PDT
(In reply to youenn fablet from comment #29)

> Thanks for the detailed report, this helps a lot.

You're welcome.

> > * On the third pageview, devtools shows a single font request initiated by the <link preload tag - but this request fails due to CORS permissions.
> 
> I am surprised here given it seems you always provide ACAO:*.
> It would fail due to CORS permissions if we were doing a CORS with
> credentials fetch, but I assume preload should be using CORS no-credentials.
> Maybe there is a bug here (independently of the particular font CORS issue)
> we could try to further investigate.


Apologies, re-reading that bit I wasn't quite clear.

We are serving fonts through Amazon CloudFront. That sends ACAO:* response headers on all *CORS* requests (e.g. with an Origin: header). But it is not possible to configure CloudFront to send any CORS response headers on a non-CORS request.

So on pageview#2 the cache is overwritten by the response from the font request, and that does not have ACAO headers. Then on pageview#3 the crossorigin preload attempts to use that cached response and of course hits the CORS permission error.

If that makes sense?


> @acoulton, is there way for us to reproduce what you are seeing?

I can't share the production example, but I'll see if I can put a repro case together.