26

I am having problems serving static assets to Firefox using AWS Cloudfront.

Chrome works perfect, but Firefox is returning a CORS error.

If I execute curl , I get:

HTTP/1.1 200 OK
Content-Type: application/x-font-opentype
Content-Length: 39420
Connection: keep-alive
Date: Mon, 11 Aug 2014 21:53:50 GMT
Cache-Control: public, max-age=31557600
Expires: Sun, 09 Aug 2015 01:28:02 GMT
Last-Modified: Fri, 08 Aug 2014 19:28:05 GMT
ETag: "9df744bdf9372cf4cff87bb3e2d68fc8"
Accept-Ranges: bytes
Server: AmazonS3
Age: 2743
X-Cache: Hit from cloudfront
Via: 1.1 c445b20dfbf3128d810e975e5d84e2cd.cloudfront.net (CloudFront)
X-Amz-Cf-Id: ...

Which I think needs the header:

Access-Control-Allow-Origin: *

Can anyone help me? Why is it a problem on Firefox and not Chrome? How can I solve it?

Tony
  • 425
  • 2
  • 5
  • 14

4 Answers4

21

First thing, you need to make sure that you whitelist origin header:

If you want CloudFront to respect cross-origin resource sharing settings, configure CloudFront to forward the Origin header to your origin.

http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/RequestAndResponseBehaviorCustomOrigin.html#request-custom-cors

Also see: http://aws.amazon.com/blogs/aws/enhanced-cloudfront-customization/

By the way, there are several similar questions on serverfault/stackoverflow and a lot of answers.

bjunix
  • 326
  • 2
  • 4
17

Update:

None of this is needed anymore as cloudfront now has proper support for this. Refer to: https://aws.amazon.com/about-aws/whats-new/2021/11/amazon-cloudfront-supports-cors-security-custom-http-response-headers/ https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/adding-response-headers.html

Previous response:

This is a bit more complicated than the accepted answer indicates.

The CORS support when using Cloudfront + S3 is actually implemented in S3 and it works like this according to Amazon:

The request's Origin header must match an AllowedOrigin element.

The request method (for example, GET or PUT) or the Access-Control Request-Method header in case the of a preflight OPTIONS request must be one of the AllowedMethod elements.

Every header listed in the request's Access-Control-Request-Headers header on the preflight request must match an AllowedHeader element.

What may not be clear is that if no Origin header is sent by the client, then this processing will not happen. And we're using Cloudfront in front which, if you're just hosting static assets, you've probably set up to ignore all headers. The result is that if the first request to each file from a specific edge node doesn't include the Origin header, it will cache the response without the Access-Control-Allow-Origin header, resulting in CORS failures.

The result is that the first incoming request will determine which headers are returned for all requests until the cache expires.

There are ways to fix/workaround this.

  • Enable conditional caching based on the "Origin" header.

This works fine if you expect only a few or a single origin, but otherwise your caching ratio could become really bad.

  • Use Lambda@edge to forcibly set the headers, this can be done just once for each origin (S3) request.

Fully flexible, but adds overhead and cost.

  • Override the "Origin" header to a dummy value for every request.

This is done by inserting some random domain name in the "Origin Custom Headers". Anything like "example.org" will work fine, this will cause the S3 processing to always run and if configured correctly S3 will then return "Access-Control-Allow-Origin: *".

This is only really useful in the "Access-Control-Allow-Origin: *" case and it's a bit of a hack, but it's probably the best current solution when hosting static assets on cloudfront + S3.

Rasmus Larsen
  • 171
  • 1
  • 3
  • This S3 behavior is very dangerous ! We've been bitten by this in production multiple times. First request does not contain the "origin" header, and cached response in cloudfront won't have any CORS headers. Files will be blocked by CORS until cache expires or is invalidated. Thanks for this answer, it allowed me to narrow down on this very sneaky problem ! – Starscream Mar 08 '21 at 15:24
4

I came across this problem today, where some font files (*.woff/*woff2) on S3 being served via CloudFront had lost their Access-Control-Allow-Origin response header, resulting in CORS errors from web browsers. I expect a web crawler (or something else) had requested the files without the Origin request header present, resulting in a cached copy of the fonts without the necessary Access-Control-Allow-Origin header.

Fortunately, Amazon has now introduced CloudFront Functions which can modify request and response headers among other things, as a lower cost alternative to Lambda@edge. They have an example function specifically for adding the Origin header if it's missing, here:

https://github.com/aws-samples/amazon-cloudfront-functions/tree/main/add-origin-header

This is working well for me.

Stuart Welch
  • 141
  • 1
0

For a simple use case, I built a CloudFront + S3 origin solution to provide HTTPS and CORS settings for a static website.

Using the new CloudFront managed response header policies simplifies the CORS settings for CloudFront.

However, I have still experienced CORS problems with these policies.

I had an Ajax request making cross-origin requests from different domains to fetch a HTML resource, and I would intermittently get CORS errors because the response had an Access-Control-Allow-Origin header for a different domain.

It appears that the CloudFront CDN was caching this header (despite using all of the recommended 'out-of-the-box' settings). With all of the history of this issue it was difficult to boil it down to the right thing.

Eventually, we realised that we had also configured a CORS policy on the S3 bucket (with allowed origins etc), and this was interfering with the CloudFront policies. Although you cannot see it when you browse the CloudFront response policy settings in AWS console (it would be nice if AWS added this), it appears that the default CORS policies in CloudFront do NOT override the origin settings. So the S3 CORS responses were being cached by CloudFront leading to the issue.

The solution was to clear the CORS policy in S3 permissions, and let CloudFront take care of all of the CORS headers.

Hope this helps someone (or my future self remembering this issue).

AlexW
  • 1