Cloudfront使用签名的URL来获取S3对象的间歇性403 CORS错误(访问控制允许来源)

时间:2019-02-10 00:33:36

标签: amazon-web-services amazon-s3 cors pre-signed-url amazon-cloudfront

简介

为了使上载的媒体(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

The error, from Safari in this case.

此错误(错误)已在所有环境中得到确认:localhost,dev.myapp.com,prod.myapp.com。以及所有平台/浏览器。

由于缺乏韵律或原因,我实际上开始认为这是一个AWS错误(它们确实会不时发生)。


到目前为止的调试清单

几天来我一直在想着要解决这个问题。到目前为止,这是我尝试过的事情:

  

您尝试过其他浏览器/平台吗?

     

是的。此问题存在于所有客户端来源,浏览器(和   版本),以及所有平台。   

     

您的S3存储桶是否正确配置了CORS?

     

是的。实际上,它是完全开放的。我什至将<MaxAgeSeconds>0</MaxAgeSeconds>设置为   为了防止用户缓存任何飞行前OPTIONS请求   客户:

     

CORS settings   

     

签名的URL是否已过期?

     

不。所有签名的URL都设置为在生成后24小时过期。这个问题甚至出现了几秒钟   在生成任何给定的签名URL之后。   

     

用于生成签名URL的方法是否存在问题?

     

不太可能。我只是在使用AWS.CloudFront.Signer.getSignedUrl()   JS SDK的方法。签名的URL do 大部分时间都有效,因此   签名会出现问题似乎很奇怪   处理。同样,该错误显然是CORS错误,而不是签名   不匹配错误。   

     

是时区/服务器时钟问题吗?

     

不。该系统确实跨多个时区为用户提供服务,但是   考虑到签名的URL都是生成的,因此理论证明是错误的   在服务器端。客户端的时区无关紧要   从生成之日起24小时内都有效的签名URL   TZ在里面。   

     

您的CF发行版是否配置正确?

     

是的,据我所知,遵循几个AWS guides,   tutorialsdocs and such

     

为简洁起见,以下是屏幕截图。您可以看到我已被禁用   完全进行缓存以试图排除这种情况:

     

CF distro config   

     

您是否看到所有MIME类型的错误?

     

不。没有发现任何图像,音频或视频文件的错误   (对象)。经过大量测试,该错误似乎只会   尝试获取文档或PDF文件(.doc,.docx,   .pdf)。这使我相信这只是一个Accept标头   不匹配错误:客户端正在发送带有标头的XHR   Accept: pdf,但实际上是为Accept: application/pdf生成了签名。   我还不能完全排除这种情况   原因。但是考虑到错误是   断断续续的。因此,如果这是Accept标头不匹配的问题,那么它   每次都会出错。

     

此外,XHR正在发送Accept: */*,因此问题出在这里的可能性很小。



问题

我真的碰壁了。谁能看到我在这里想念的东西?我能想到的最好的是,这是某种“时机”问题。哪种时序问题,或者甚至是时序问题,我还没有弄清楚。

在此先感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

在serverfault上找到了相同的解决方案。

https://serverfault.com/questions/856904/chrome-s3-cloudfront-no-access-control-allow-origin-header-on-initial-xhr-req

  

您显然无法成功地从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);
};