
Yeah, you wish this was about beer.
So you’re using some trick Web fonts for your site or app. It looks awesome in development. Yay.
You push to production, where your assets are all hosted on a CDN and suddenly your fonts stop working on Firefox and probably Internet Explorer (9+), too. You see crappy little squares where awesome fonts should be.
Bang. You’ve just run into the browsers’ same-origin policy restrictions.
I experienced this problem on Schock.net, where my assets are hosted on Amazon S3 with Cloudfront as the CDN. I installed the Font Awesome pack, which is loaded like so with the CSS3 @font-face
rule:
@font-face {
font-family: 'FontAwesome';
src: url('../font/fontawesome-webfont.eot?v=3.2.0');
src: url('../font/fontawesome-webfont.eot?#iefix&v=3.2.0')
format('embedded-opentype'),
url('../font/fontawesome-webfont.woff?v=3.2.0') format('woff'),
url('../font/fontawesome-webfont.ttf?v=3.2.0') format('truetype'),
url('../font/fontawesome-webfont.svg#fontawesomeregular?v=3.2.0')
format('svg');
}
@font-face
causes requests to http://static.schock.net/font
. So with the origin being at http://schock.net
and the CDN being a different domain, the browser is all like, NUH-UH! Fonts denied!
Just tell me how to fix it already
Assuming you’re using S3, the fix is in your CORS configuration in your S3 bucket configuration:
- Go to your AWS console.
- Choose your bucket.
- Choose Properties.
- Choose Edit CORS Configuration.
Here is the basic XML (via StackOverflow) for allowing your fonts to be loaded from a specified origin. You’ll need to modify it to work with your particular setup.
<CORSConfiguration>
<CORSRule>
<AllowedOrigin>http://mydomain.com</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<AllowedHeader>Content-*</AllowedHeader>
<AllowedHeader>Host</AllowedHeader>
</CORSRule>
<CORSRule>
<AllowedOrigin>http://*.mydomain.com</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<AllowedHeader>Content-*</AllowedHeader>
<AllowedHeader>Host</AllowedHeader>
</CORSRule>
</CORSConfiguration>
Be patient. I monkeyed around with my config and it worked at first, then later it didn’t. There are some caching issues going on here, so if you get it wrong and want to update the CORS config, you will probably want to invalidate your font files via the AWS Cloudfront interface.
Update 10/7/2014: Cloudfront cache invalidation only seems to be necessary if you are updating font file versions. Instead, there seems to be perhaps 5-10 minutes of delay from when you update the bucket policy XML to when it actually gets propagated to Cloudfront. Be patient.
Some people suggest the fix is <AllowedOrigin>*</AllowedOrigin>
. Sure, this will probably work, but you’ve also just allowed every asset in your bucket to be accessed by any domain without any cross-origin restrictions. Problem? Maybe.
And what’s up with the AllowedHeader
rules, you’re wondering? These are for CORS preflight requests, and if a preflight request asks for these headers, then this says that these are the ones that are ok to send with the actual request. Why they’re necessary to make your Web fonts work isn’t entirely clear, but it seems like it might get around a Firefox bug, according to the StackOverflow article. (Yes, CORS preflight is confusing.)
So why CORS?
Because same-origin policy. CORS is a way by which to relax this policy; it’s an alternative to JSONP minus some of the security concerns that script injection is subject to.
But why are *fonts* restricted by same-origin policy in Firefox and IE?
Yes, what a fantastic question. The simple answer is that the same-origin restriction for fonts is in the CSS3 Fonts working spec, and Firefox and IE are adhering strictly to this.
But fonts aren’t scripts. They can’t be executed to do malicious things. So the deeper question is, what’s the motivation behind this?
Same-origin policy was a security feature, and now it seems like the purpose is being inflated onto the slippery slope of intellectual property control. That is to say, font foundries, who command wheelbarrows full of money to license their fonts, don’t want it to be easy for freeloaders to illegally use their fonts with a simple @font-face
rule pointing to a legally licensed domain.
This seems like a whole separate W3 standards discussion altogether, no? So my guess is that the Google Chrome folks don’t agree with this interpretation, and that’s why Chrome doesn’t apply same-origin policy to fonts as of yet.
Of course, I’m speculating somewhat, so take it with a grain of salt can of Coors.
Update 12/2014
A Google engineer wrote a whole book on the subject of CORS! I haven’t read it, but probably worth a look if you need something in-depth.
More CORS reading
- Mozilla: HTTP access control (CORS)
- HTML5 Rocks: Using CORS
- Nicholas Zakas: Cross-domain Ajax with Cross-Origin Resource Sharing
- Amazon CORS configuration
- Bugzilla: Same domain policy for @font-face. really?!?
- CORS in Action: Creating and consuming cross-origin APIs