'Access-Control-Allow-Origin' doesn't appear in the object storage!
in the cloud manager I can see the 'CORS enabled' is on!
but the 'Access-Control-Allow-Origin' header doesn't appear!
can you fix the bug … ??
Thanks!
3 Replies
Hello!
I wanted to make sure that our Object Storage systems were honoring CORS policies correctly, so I performed an investigation. This investigation will use the s3cmd command to access Object Storage. If you're not familiar with this command, you can review our documentation on it:
https://www.linode.com/docs/guides/how-to-use-object-storage/#s3cmd
The below commands reference an example bucket named mybucket
on the us-east-1
cluster, and a test image asset called testimage.png
. If you want to follow along, you can replace these names with your own bucket/asset names.
First, you can verify that the CORS policy is set on your bucket by running the info
command on the bucket:
s3cmd info s3://mybucket
It should respond with this line in the output:
CORS: <CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><CORSRule><AllowedMethod>GET</AllowedMethod><AllowedMethod>PUT</AllowedMethod><AllowedMethod>DELETE</AllowedMethod><AllowedMethod>HEAD</AllowedMethod><AllowedMethod>POST</AllowedMethod><AllowedOrigin>*</AllowedOrigin><AllowedHeader>*</AllowedHeader></CORSRule></CORSConfiguration>
This CORS configuration has the AllowedOrigin
parameter set to the wildcard (*
) domain.
I found that the Access-Control-Allow-Origin header for an Object Storage-hosted asset will appear in the response, but only if an Origin is included in your request's headers. For example, review this curl command that explicitly sets an Origin domain with the -H
flag:
curl -I -H "Origin: http://example.com" https://mybucket.us-east-1.linodeobjects.com/user-template/testimage.png
HTTP/1.1 200 OK
Date: Fri, 02 Apr 2021 16:24:54 GMT
Content-Type: image/png
Content-Length: 610137
Connection: keep-alive
Accept-Ranges: bytes
Last-Modified: Wed, 31 Mar 2021 11:24:08 GMT
x-rgw-object-type: Normal
ETag: "78e172c284663914fd19c69e2e4f52e4"
x-amz-request-id: tx000000000000004f4e411-0060674556-2fb8550-default
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: HEAD
Furthermore, the Access-Control-Allow-Origin header will only appear if your request's Origin domain also matches the domain listed in your Access-Control-Allow-Origin. The above request used the Origin http://example.com
, which matches the wildcard (*
) domain set in your Access-Control-Allow-Origin, so the header will appear in your response. However, if you had instead explicitly set this header to a different domain (e.g. http://example2.com
), then the Access-Control-Allow-Origin header will not appear in the response.
If you want to try setting an explicit domain in your CORS policy, you could create a .xml file with the AllowedOrigin
set to that domain. If you want to follow along with the following example, you can do that with your existing Object Storage bucket, or you could create another bucket temporarily for testing purposes.
For example, create a testcors.xml file and paste in this snippet. This snippet specifies http://example.com
as your allowed origin domain:
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>PUT</AllowedMethod>
<AllowedMethod>DELETE</AllowedMethod>
<AllowedMethod>HEAD</AllowedMethod>
<AllowedMethod>POST</AllowedMethod>
<AllowedOrigin>http://example.com</AllowedOrigin>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
Then run this command to set the new policy:
s3cmd setcors testcors.xml s3://mybucket
Verify that the new CORS policy is set:
s3cmd info s3://mybucket
CORS: <CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><CORSRule><ID>Alloweverything</ID><AllowedMethod>GET</AllowedMethod><AllowedOrigin>http://example.com</AllowedOrigin><AllowedHeader>*</AllowedHeader><MaxAgeSeconds>3000</MaxAgeSeconds></CORSRule></CORSConfiguration>
Finally, another way to test out that CORS works is to embed a test image hosted on Object Storage in an HTML page with the crossorigin
attribute set. For example, create a test.html, paste in this snippet, and save the file:
<img crossorigin src="https://mybucket.us-east-1.linodeobjects.com/user-template/testimage.png">
If you ran the above s3cmd setcors testcors.xml s3://mybucket
command, then when you load the test.html file in your browser, the image link should be broken. This is because the Origin sent by your computer (which would be null
for an HTML page that is stored on your filesystem) doesn't match the Access-Control-Allow-Origin
you set in the new policy (which was http://example.com
). If you are using Chrome, you can also see a CORS error
status appear if you look at the Network tab in the Dev tools:
https://developer.chrome.com/docs/devtools/network/
After finishing with these examples, you may want to reset your CORS policy back to the wildcard domain. To do that, update testcors.xml with the following snippet and then run s3cmd setcors testcors.xml s3://mybucket
again:
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>PUT</AllowedMethod>
<AllowedMethod>DELETE</AllowedMethod>
<AllowedMethod>HEAD</AllowedMethod>
<AllowedMethod>POST</AllowedMethod>
<AllowedOrigin>*</AllowedOrigin>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
Hi @nmelehan
Thanks for the help!
However, I'm wondering if this is the correct behavior:
I found that the Access-Control-Allow-Origin header for an Object Storage-hosted asset will appear in the response, but only if an Origin is included in your request's headers.
Since I already set the Access-Control-Allow-Origin
as *
Why not always make it appear in the response?
Because I think AWS s3
and Digital Ocean Spaces
are acting like that.
What do you think?
I have some users having trouble with this when loading assets via JavaScript.
Can this be considered as a bug and reported to the dev team?
Thanks a lot!
I found that the Access-Control-Allow-Origin header for an Object Storage-hosted asset will appear in the response, but only if an Origin is included in your request's headers.
Yes, I believe this is the correct behaviour.
According to the CORS spec, it is opt-in:
It needs to be an opt-in mechanism to prevent leaking data from responses behind a firewall (intranets).
By not providing the Origin header, you are not opting in to CORS, and will not get the relevant policy (e.g. Access-Control-Allow-Origin) back.