40

I am having trouble forcing S3 to set CORS headers on all of the objects it returns from a bucket, though CORS is enabled, as client-side S3 uploads is working, the returned objects do not have CORS headers!

The policy I have enabled is :

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <AllowedMethod>POST</AllowedMethod>
        <AllowedMethod>PUT</AllowedMethod>
        <AllowedHeader>*</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

An example object URL https://s3.amazonaws.com/captionable/meme/test

Does anyone know what is wrong?

Cory Dolphin
  • 2,650
  • 1
  • 20
  • 30

5 Answers5

53

First of all, make sure an Origin header with every request. If no Origin header is sent, S3 won't send access-control headers, as S3 deems them irrelevant (and typically, they are). A browser (for which the CORS mechanism is meant) will automatically send an Origin header when doing cross-origin HTTP requests through XMLHTTPRequest.

In case of loading images with img, you need to add crossorigin="anonymous" attribute. See MDN Documentation on crossorigin attribute. This will cause the browser to send an Origin request header like it does with XMLHTTPRequest.

Going by the answer of Sam Selikoff, you may need to change

 <AllowedOrigin>http://*</AllowedOrigin>

to

 <AllowedOrigin>http://*</AllowedOrigin>
 <AllowedOrigin>https://*</AllowedOrigin>

I haven't tested this.

Going by Paul Draper's comment on this answer: Watch out for caching issues. A browser may use a cached response that did not include the appropriate Access-Control response headers. During development, you can clear your cache. In production, you must switch to a new URL for the resource, if it was used in a static manner before.

Myrne Stol
  • 11,222
  • 4
  • 40
  • 48
  • 6
    And therein lies the rub. I was creating an image tag, which does not send Origin headers. That said, I expected S3 to always return CORS headers, though it only does so when 'Origin' is specified. Thanks for the confirmation that CORS is properly configured. – Cory Dolphin Jul 10 '13 at 15:06
  • In that case, it seems that I should be setting the crossOrigin attribute of an image tag. Do you by any chance know the sup – Cory Dolphin Jul 10 '13 at 18:14
  • 2
    I don't have any experience with that attribute. Setting it to "anonymous" might just trigger the browser to send the `Origin` header. Maybe post separate question? – Myrne Stol Jul 10 '13 at 20:23
  • 1
    Also, the request needs to be a GET and not a HEAD. To test this with curl : `curl -iH "Origin: test" http://…` – Sunny Apr 30 '14 at 19:27
  • 7
    This answer is mostly correct, but it is most certainly not irrelevant. If the response without CORS is cached, the next request will retrieve a CORS-less response and fail. – Paul Draper Jan 26 '16 at 17:14
  • 3
    Adding ` * GET 3000 Authorization ` workes for me. But this only works if I open developer console and goto networks tab and check the 'disable cache'. Doesn't work without opening the developer console. – Arjun Nayak Jun 21 '17 at 14:28
  • You may need to add `HEAD` to the `AllowedMethod`s – bimbom22 Sep 18 '17 at 21:48
  • 2
    is it possible to force S3 to send headers back in response even though ORIGIN is not present in request ? – strix25 Oct 26 '22 at 16:13
31

I also ran into this with an <image> tag, and after following Myrne Stol's answer I added the crossorigin=anonymous tag to my image tag. I verified that the Origin header was indeed being sent to S3, but still, the Access-Control-Allow-Origin header was not being sent in response.

I came across this SO answer and it solved it. I changed the AllowedOrigin in my S3 config to this:

<AllowedOrigin>http://*</AllowedOrigin>
<AllowedOrigin>https://*</AllowedOrigin>

and now S3 responds with the access headers. Yay!

Community
  • 1
  • 1
Sam Selikoff
  • 12,366
  • 13
  • 58
  • 104
  • 2
    @cory-dolphin I think this should be the accepted answer here. I too had the same problem with the image tag and adding these two lines fixed it. – supersan Jul 16 '15 at 08:30
  • 2
    This isn't working for me (~2 years later). I've changed the configuration and I'm testing both in Postman & with a – carpiediem Dec 22 '17 at 03:51
  • You also have to include an Origin header in any request - this threw me using curl (e.g. `curl -X GET -v --header "Origin: https://www.example.com" https://s3-eu-west-1.amazonaws.com/my-bucket/asset.ext` ) – John Jul 10 '18 at 18:15
28

Chrome has this amazing bug which they won't fix:

enter image description here

If you're lucky enough to have control over the code that is generating the tag you can add crossorigin="anonymous" to the tag.
Like <img src="foo.bar/baz.jpg" crossorigin="anonymous" />
If you can modify either the URL for the tag or the URL for the XHR request, you could add a query parameter to one of them to bypass the cache.
Like foo.bar/baz.jpg?x-request=xhr.

Safari has this issue too btw.

Forivin
  • 14,780
  • 27
  • 106
  • 199
  • NGL I've been struggling to find an explanation for *hours* this should be upvoted more, as it was the real reason I had issues - I would have never thought that having an (or in my case even *background-image* in css) would change the behavior of the JS code used afterward. You're a savior. – Sebastian Di Luzio Mar 08 '21 at 13:37
  • 2
    I think the real issue is that the server varies the response based on whether or not the origin header is included, but doesn't include "Vary: Origin" in the response. So caches are perfectly entitled to return the response without the CORS headers as the server has allowed it to be cached. I assume the server we're talking about here is S3 - I'm posting a bug report to ask them to fix their broken behaviour. The fetch spec has a clear description that S3 is violating: https://fetch.spec.whatwg.org/#cors-protocol-and-http-caches – tangobravo Jun 26 '21 at 17:46
3

TLDR; Make sure that every image or video element that requests a resource which (somewhere) needs CORS uses crossorigin="anonymous"

I ran into this issue for a video element that was exporting to a canvas. The CORS was setup in S3 correctly, but it still gave me an error and refused to play the video.

It turned out there was a second video element pointing to the same resource, and that video element didn't have crossorigin="anonymous". Hence, the second video played fine since it wasn't expecting an access-control header, but the server response was cached and blocked the first video from playing because the cached server response didn't have an access-control header

d2vid
  • 2,014
  • 1
  • 22
  • 25
0

I have faced an issue where I was not getting the CORS header from s3 issue is the origin sent from the chrome is with www like https://www.example.com while on s3 we have allowed only https://example.com So s3 wont send the CORS in case of Origin name mismatch

Just shared in case someone will face similar situation

Waqas Ahmed
  • 1,321
  • 1
  • 14
  • 23