【问题标题】:AWS S3 Not Sending Access-Control-Allow-Origin header when Origin header on request is present当请求的 Origin 标头存在时,AWS S3 不发送 Access-Control-Allow-Origin 标头
【发布时间】:2016-09-25 22:24:54
【问题描述】:

我有一个采用以下 CORS 策略的 AWS S3 存储桶:

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

在我的应用程序中,我从存储桶中加载了一页图像。图像按预期显示在页面上。当我在 Adob​​e Creative SDK 中单击其中一个图像以将其打开时,SDK 无法加载该图像,因为它被 CORS 阻止。 SDK 获取图像的 url 并通过 AJAX 加载它。 SDK 有一个启用 CORS 的选项,并且似乎正在发送正确的 Origin 标头(参见屏幕截图),但 AWS 不包括 Access-Control-Allow-Origin-Header,导致图像被 CORS 阻止。

我已经搜索了关于这个主题的所有问题,似乎没有人有一个直接的答案。关于这个主题有几十个问题没有得到解答,但是在许多情况下,AJAX 请求似乎没有发送 Origin 标头或存储桶配置不正确。在这种情况下,这些都不正确,这就是 这不是重复的原因。

正如您在屏幕截图中看到的,请求包含 Origin 标头,但响应不包含 Access-Control-Allow-Origin 标头。我想知道的是: 1. 如果我的存储桶配置正确,为什么 S3 没有发送正确的标头? 2. Adob​​e Creative SDK 通过 AJAX 请求图像时,浏览器看到图像已经缓存并尝试提供缓存的图像(没有Origin 标头)是可能的吗? 3.如果是#2,如何在图片请求中强制添加Origin头?在应用中,图片是一个 div 的背景(css background-image 属性)。

【问题讨论】:

  • 显然这是在您的缓存中,并且似乎已使用原始请求中设置的 Origin 标头进行缓存...所以,第一个问题是,它是否在您配置 CORS 之前到达那里桶?
  • 这在生产中是可能的,但我要经常清除缓存,所以我会说缓存中的图像会在 CORS 之后被请求制定了政策。不过,每张图片有两个请求,所以我不确定这是否会有所不同。第一个请求是浏览器发送的标准 http get 请求。第二个是SDK发送的ajax请求。

标签: ajax amazon-web-services amazon-s3 cors


【解决方案1】:

我创建了一个测试存储桶,启用了 CORS,并使用了您的 CORS 规则。

请注意,我不相信&lt;ExposeHeader&gt;Access-Control-Allow-Origin&lt;/ExposeHeader&gt; 是必要的,但它不会因为出现而造成任何伤害,所以我保留了它。

我在测试中观察到的行为与您在浏览器的请求/响应标头中显示的内容不一致

使用 curl,我将 Origin: 标头设置为 http://example.com。 (是的,这实际上是我设置的......这在下面的输出中没有修改)。

$ curl -v http://xxxxxxxxxxxx.s3.amazonaws.com/index.txt -H 'Origin: http://example.com'
* Hostname was NOT found in DNS cache
*   Trying 54.231.98.120...
* Connected to xxxxxxxxxxxx.s3.amazonaws.com (54.231.98.120) port 80 (#0)
> GET /index.txt HTTP/1.1
> User-Agent: curl/7.35.0
> Host: xxxxxxxxxxxx
> Accept: */*
> Origin: http://example.com
>
< HTTP/1.1 200 OK
< x-amz-id-2: pF39K26ii42SzxSU2Dt0KT2z7+xmfyiP4yekp9s4DCYJo0jlRwCTDg6QO6f0HMIL4H9b640zq7U=
< x-amz-request-id: 3B18A563CFF4E485
< Date: Sat, 28 May 2016 21:49:21 GMT
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Methods: GET
< Access-Control-Expose-Headers: Access-Control-Allow-Origin
< Vary: Origin, Access-Control-Request-Headers, Access-Control-Request-Method
< Cache-Control: no-cache
< Last-Modified: Sat, 28 May 2016 21:40:57 GMT
< ETag: "cd21a8c7268dc6af728d180f9a3a81d7"
< Accept-Ranges: bytes
< Content-Type: text/plain
< Content-Length: 71
* Server AmazonS3 is not blacklisted
< Server: AmazonS3

为什么这很有趣?

S3,配置了 CORS 并且 &lt;CORSRule&gt; 匹配您的请求,总是返回 CORS 响应标头 Vary:标头(这意味着“如果您改变您的请求中的以下标头之一,我的响应可能会有所不同。”)我所指的上述输出中的标头是这些。

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET
Access-Control-Expose-Headers: Access-Control-Allow-Origin
Vary: Origin, Access-Control-Request-Headers, Access-Control-Request-Method

我只能找到一个例外,那就是没有匹配的 CORS 规则。为了证明这一点,我首先将我的 CORS 配置更改为 &lt;AllowedOrigin&gt;http://example.com&lt;/AllowedOrigin&gt;,然后重复请求。请注意,响应几乎相同,只是 S3 在响应中使用了确切的来源,并添加了Access-Control-Allow-Credentials

< Access-Control-Allow-Origin: http://example.com
< Access-Control-Allow-Methods: GET
< Access-Control-Expose-Headers: Access-Control-Allow-Origin
< Access-Control-Allow-Credentials: true
< Vary: Origin, Access-Control-Request-Headers, Access-Control-Request-Method

...但是,如果我 - 仍然使用指定特定来源的更严格的 CORS 规则 - 然后发送对 Origin: example.org 的请求,这是我的 CORS 配置中未提及的来源并且没有通配符&lt;AllowedOrigin&gt; 匹配,S3 响应好像根本没有配置 CORS。

< HTTP/1.1 200 OK
< x-amz-id-2: WJ0QmIZ6jTQYefFi8GjlDQkZKFHDX8/5cmejeulhG1ov3/NdoSXbsTKetYpxvXPML8aUnPNZ/ac=
< x-amz-request-id: 15A03D8B1E08A830
< Date: Sat, 28 May 2016 21:58:34 GMT
< Cache-Control: no-cache
...etc.

这让我回到了最初的结论,即您向浏览器显示的请求与您为 CORS 配置存储桶的时间不匹配,并且可能在存储桶的 CORS 设置处于正确状态之前已被缓存,或者在他们匹配您在问题中发布的内容之前。

如果该请求中存在 Origin: 标头,正如浏览器显示的那样,那么 S3 应该添加 CORS 响应标头,无论该请求实际上是否是跨域请求。

您接下来的步骤是在不可能被缓存的新路径上尝试使用新对象,或者尝试在发出请求时将?some-random=thing-here 添加到对象的 URL 的常见浏览器缓存破坏策略.如果做不到这一点,您应该考虑使用curl 之类的工具来证明或反驳您的存储桶的正确行为,该工具可以准确显示请求/响应中发生的情况。

【讨论】:

  • 我对一些新图像进行了更多测试,以确保没有预先缓存的可能性。我发现(至少在 Safari 中),网络选项卡告诉我第二个请求是从缓存中提供的。因此,即使它具有正确的标头,但不知何故,浏览器仍在提供没有 Origin 标头的缓存版本。我决定尝试您向 url 添加随机查询参数的方法,到目前为止它似乎一直保持下去。
  • 好的,这是一个建议。将您的存储桶 CORS 配置更改为 &lt;AllowedOrigin&gt;http://example.com&lt;/AllowedOrigin&gt;(使用您的实际域)。如果您有多个(同一主机的 https 与 http 的来源不同),则为每个来源创建一个相同的 &lt;CORSRule&gt;...&lt;/CORSRule&gt; 块。 Safari 可能会在没有实际告诉你的情况下使用通配符调用 BS。
  • 没有骰子。我试过这种方法。我创建了一个具有特定来源和通配符来源的策略,但它失败了。还尝试仅使用特定来源(无通配符规则),但仍然失败。我很确定这是一个缓存问题。你建议的缓存破坏技巧是唯一对我有用的方法。
  • @ACIDSTEALTH 我相信你一直都是正确的......你的问题可能确实是缓存问题,这是 S3 的一个问题行为。它应该在非 CORS 响应中返回 Vary: Origin,但事实并非如此。有关问题的分析和使用 Lambda@Edge 的解决方法,请参阅 serverfault.com/a/856948/153161
  • 有趣的发现在那里!如果我没记错的话,我最终只是在每个文件名的末尾附加了一个查询字符串(例如 utm=1234556789),并带有一个 unix 时间戳,以强制浏览器再次请求该文件。
猜你喜欢
  • 2019-03-08
  • 2018-07-27
  • 2018-06-20
  • 1970-01-01
  • 2015-11-18
  • 1970-01-01
  • 2018-10-28
  • 2020-01-24
相关资源
最近更新 更多