缓存图像的 CORS 策略

Posted

技术标签:

【中文标题】缓存图像的 CORS 策略【英文标题】:CORS policy on cached Image 【发布时间】:2012-09-20 20:35:34 【问题描述】:

在 chrome 22 和 safari 6 中。

使用支持 CORS 的 S3 存储桶从 s3 加载图像以在画布中使用(以提取为主要意图),代码如下:

<!-- In the html -->
<img src="http://s3....../bob.jpg" /> 

// In the javascript, executed after the dom is rendered
this.img = new Image();
this.img.crossOrigin = 'anonymous';
this.img.src = "http://s3....../bob.jpg";

我观察到以下情况:

    禁用缓存 一切正常,两个图像都加载了

然后尝试启用缓存:

    启用缓存 DOM 图像加载,画布图像创建 dom 安全异常

如果我修改代码的 javascript 部分以附加查询字符串,如下所示:

this.img = new Image();
this.img.crossOrigin = 'anonymous';
this.img.src = "http://s3....../bob.jpg?_";

一切正常,即使完全启用缓存。通过使用 http 代理并观察到在失败的情况下,实际上并没有从服务器请求图像,我了解到缓存是一个问题。

我不得不得出的结论是图像缓存正在保存原始请求标头,然后将其用于后续启用 CORS 的请求 - 由于违反同源策略而产生了安全异常.

这是预期的行为吗?

编辑:在 Firefox 中工作。

Edit2:s3 存储桶上的 Cors 策略

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

我正在使用全开,因为我现在只是在本地机器上进行测试。这还没有生产。

Edit3:更新了 cors 政策以指定来源

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

已验证的传出标头:

Origin  http://localhost:5000
Accept  */*
Referer http://localhost:5000/builder
Accept-Encoding gzip,deflate,sdch
Accept-Language en-US,en;q=0.8
Accept-Charset  ISO-8859-1,utf-8;q=0.7,*;q=0.3

传入的标头:

Access-Control-Allow-Origin http://localhost:5000
Access-Control-Allow-Methods    GET
Access-Control-Allow-Credentials    true

如果我在加载到画布时没有破坏缓存,Chrome 仍然会失败。

编辑 4:

刚刚在失败案例中注意到了这一点。

传出标题:

GET /373c88b12c7ba7c513081c333d914e8cbd2cf318b713d5fb993ec1e7 HTTP/1.1
Host    amir.s3.amazonaws.com
User-Agent  Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.91 Safari/537.4
Accept  */*
Referer http://localhost:5000/builder
Accept-Encoding gzip,deflate,sdch
Accept-Language en-US,en;q=0.8
Accept-Charset  ISO-8859-1,utf-8;q=0.7,*;q=0.3
If-None-Match   "99c958e2196c60aa8db385b4be562a92"
If-Modified-Since   Sat, 29 Sep 2012 13:53:34 GMT

传入的标头:

HTTP/1.1 304 Not Modified
x-amz-id-2  3bzllzox/vZPGSn45Y21/vh1Gm/GiCEoIWdDxbhlfXAD7kWIhMKqiSEVG/Q5HqQi
x-amz-request-id    48DBC4559B5B840D
Date    Sat, 29 Sep 2012 13:55:21 GMT
Last-Modified   Sat, 29 Sep 2012 13:53:34 GMT
ETag    "99c958e2196c60aa8db385b4be562a92"
Server  AmazonS3

认为这是第一个请求,由 dom 触发。我不知道这不是javascript请求。

【问题讨论】:

它可以在 Firefox 或 Opera 中使用吗? 你解决过这个问题吗? 你试过Access-Control-Allow-Origin *吗?因为http://localhost:5000/ 可能会产生误导。 嗨!你解决了吗?谢谢!! 像 chemitaxis 一样,我看不出解决方案是什么。您能告诉我们这是如何解决的吗? 【参考方案1】:

问题是图像是从以前的请求中缓存的,没有所需的 CORS 标头。因此,当您再次请求它时,对于画布,指定了“crossorigin”,浏览器使用缓存版本,不会'看不到必要的标题,并引发 CORS 错误。 当您将“?_”添加到 url 时,浏览器会忽略缓存,因为这是另一个 URL。 看看这个线程: https://bugs.chromium.org/p/chromium/issues/detail?id=409090

火狐和其他浏览器没有这个问题。

【讨论】:

如果我们想使用缓存,我们如何缓存带有cors header的图像? 但此解决方案不适用于预签名的网址【参考方案2】:

所描述的行为似乎是合乎逻辑的,因为缓存条目键是一个目标 URI(请参阅7234 Hypertext Transfer Protocol (HTTP/1.1): Caching)。要解决此问题并有效使用缓存,您需要使图像托管服务器在两种情况下都给出相同的响应。

一种选择是让用户代理在第一个请求中也发送Origin HTTP 标头(假设带有键targetUri 的响应尚未在缓存中):

<img src="targetUri" crossorigin="anonymous" />

另一个选项是配置图像托管服务器以发送与 CORS 相关的 HTTP 标头,无论请求是否包含 Origin HTTP 标头。有关详细信息,请参阅 *** 上的 S3 CORS, always send Vary: Origin 讨论。

您还可以使用Vary 响应HTTP 标头通知用户代理响应对Origin 请求HTTP 标头敏感。缺点是用户代理可能将Vary 标头仅用作响应验证器(而不是作为缓存条目键的一部分)并且仅存储目标URI 的单个响应实例,这使得更难有效地使用缓存。有关更多信息,请查看 Mark Nottingham 的 The State of Browser Caching, Revisited 文章。

【讨论】:

您能否解释一下,当使用 img 标签在 HTML 中加载图像时如何缓存带有 CORS 标头的图像。【参考方案3】:

您应用了哪些 CORS 设置? This post 表明 AllowedOrigin 中的通配符已解析(而不是逐字发送,这似乎是未记录的行为);然后缓存 Access-Control-Allow-Origin 标头值以供后续请求使用,从而导致与您报告的问题类似。

【讨论】:

我添加了我的 cors 政策。你是说Access-Control-Allow-Origin 标头被客户端缓存了吗?我将尝试使用 localhost 作为我的来源。 经过验证,即使使用为 AllowedOrigin 指定的域,我仍然会看到这种行为。 刚刚再次验证,如果我破坏缓存,一切正常。如果我不破坏缓存,那么我的来源是通配符还是特定的都没关系。我测试了 chrome & safari & firefox。 Firefox 适用于所有情况,Chrome/Safari 似乎有这个错误。一定是 webkit 问题。 @amirpc:不,我假设您的问题是由 CloudFront 或代理缓存引起的。现在,当你指责 Chrome 时,我认为 this question may be much more relevant to your situation。 我没有看到预检请求,我正在使用 http 代理并查看并且没有选项请求通过。只需添加 If-None-Match 标头即可。 Get 在我的 cors 政策中,应该可以工作。但是,这些获取没有指定来源可能是因为缓存的版本不是来自 DOM 请求。

以上是关于缓存图像的 CORS 策略的主要内容,如果未能解决你的问题,请参考以下文章

跨域请求被阻止:同源策略不允许读取远程资源,CORS 标头中缺少令牌“缓存控制”

用浏览器缓存绕过同源策略(SOP)限制

缓存策略,AFNetworking

如何将 CORS(跨域策略)添加到 NGINX 中的所有域?

CloudFront CORS 标头被缓存,导致跨源问题

如何更改 Okhttp 中的默认缓存策略?