为了使上载的媒体(S3对象)对我的多租户系统上的所有客户端不公开,我实施了Cloudfront CDN部署并将其(及其Origin S3存储桶)配置为强制按顺序使用签名的URL获取任何对象。
首先,通过我的系统对用户进行身份验证,然后使用AWS.CloudFront.Signer.getSignedUrl()
提供的AWS JS SDK方法生成签名的URL并将其返回给他们。因此他们可以调用CF / S3来下载对象(图像,PDF,docx等)。很标准的东西。
以上方法在95%的时间内都有效。用户从我的系统中获取一个签名的URL,然后当他们进行XHR获取对象时,就可以很好地对其进行检索。
但是,抛出403的错误中有5%的时间会出现CORS错误,指出客户端起源is not allowed by Access-Control-Allow-Origin
。
此错误(错误)已在所有环境中得到确认:localhost,dev.myapp.com,prod.myapp.com。以及所有平台/浏览器。
由于缺乏韵律或原因,我实际上开始认为这是一个AWS错误(它们确实会不时发生)。
几天来我一直在想着要解决这个问题。到目前为止,这是我尝试过的事情:
您尝试过其他浏览器/平台吗?
是的。此问题存在于所有客户端来源,浏览器(和 版本),以及所有平台。
您的S3存储桶是否正确配置了CORS?
是的。实际上,它是完全开放的。我什至将
<MaxAgeSeconds>0</MaxAgeSeconds>
设置为 为了防止用户缓存任何飞行前OPTIONS
请求 客户:签名的URL是否已过期?
不。所有签名的URL都设置为在生成后24小时过期。这个问题甚至出现了几秒钟 在生成任何给定的签名URL之后。
用于生成签名URL的方法是否存在问题?
不太可能。我只是在使用
AWS.CloudFront.Signer.getSignedUrl()
JS SDK的方法。签名的URL do 大部分时间都有效,因此 签名会出现问题似乎很奇怪 处理。同样,该错误显然是CORS错误,而不是签名 不匹配错误。
是时区/服务器时钟问题吗?
不。该系统确实跨多个时区为用户提供服务,但是 考虑到签名的URL都是生成的,因此理论证明是错误的 在服务器端。客户端的时区无关紧要 从生成之日起24小时内都有效的签名URL TZ在里面。
您的CF发行版是否配置正确?
是的,据我所知,遵循几个AWS guides, tutorials,docs and such。
为简洁起见,以下是屏幕截图。您可以看到我已被禁用 完全进行缓存以试图排除这种情况:
您是否看到所有MIME类型的错误?
不。没有发现任何图像,音频或视频文件的错误 (对象)。经过大量测试,该错误似乎只会 尝试获取文档或PDF文件(.doc,.docx, .pdf)。这使我相信这只是一个
Accept
标头 不匹配错误:客户端正在发送带有标头的XHRAccept: pdf
,但实际上是为Accept: application/pdf
生成了签名。 我还不能完全排除这种情况 原因。但是考虑到错误是 断断续续的。因此,如果这是Accept
标头不匹配的问题,那么它 每次都会出错。此外,XHR正在发送
Accept: */*
,因此问题出在这里的可能性很小。
我真的碰壁了。谁能看到我在这里想念的东西?我能想到的最好的是,这是某种“时机”问题。哪种时序问题,或者甚至是时序问题,我还没有弄清楚。
在此先感谢您的帮助。
答案 0 :(得分:0)
在serverfault上找到了相同的解决方案。
您显然无法成功地从HTML获取对象,然后 通过Chrome和S3的CORS请求成功再次获取它 (使用或不使用CloudFront),原因是 实施。
在原始帖子中添加答案,以免丢失。
解决方法:
使用以下代码作为原始响应触发器,可以使用CloudFront和Lambda @ Edge解决此问题。
这会将Vary:Access-Control-Request-Headers,Access-Control-Request-Method,Origin添加到来自任何没有Vary标头的S3的响应。否则,响应中的Vary标头将不会被修改。
'use strict';
// If the response lacks a Vary: header, fix it in a CloudFront Origin Response trigger.
exports.handler = (event, context, callback) => {
const response = event.Records[0].cf.response;
const headers = response.headers;
if (!headers['vary'])
{
headers['vary'] = [
{ key: 'Vary', value: 'Access-Control-Request-Headers' },
{ key: 'Vary', value: 'Access-Control-Request-Method' },
{ key: 'Vary', value: 'Origin' },
];
}
callback(null, response);
};