问题 加载AWS CloudFront文件时获取403(禁止)


我正在使用视频应用程序并将文件存储在AWS S3上,使用默认URL https://***.amazonaws.com/*** 工作正常,但我决定使用CloudFront,这对内容交付更快。

使用CF,我一直在努力 403 (Forbidden) 使用此网址 https://***.cloudfront.net/***。我错过了什么吗?

一切正常,直到我决定从CloudFront加载指向我的存储桶的内容。

有解决方案吗?


2748
2018-01-19 16:36


起源

你没有给我们太多的继续。您使用的是预先签名的网址吗?您的存储桶策略是否根据某些请求参数拒绝请求? - Michael - sqlbot
@ Michael-sqlbot我没有使用预先签名的URL,只是标准配置。我设置的策略是只接受我的URL来加载文件。 - Shina
所以,你正在使用类似的桶策略 "Condition":{ "StringLike":{"aws:Referer":["http://www.example.com/*"]} }? - Michael - sqlbot
@ Michael-sqlbot确切地说,甚至删除仅用于测试的策略也无济于事。我有点困惑 - Shina
如果我正确读到这个,请注意您现在可以使用WAF而不是使用S3方法在CloudFront上进行Referer检查。我已经涵盖了这个 这里。 (我还要更新我的帖子,提到@ Michael-sqlbot的答案,这是v neat) - alexjs


答案:


使用检查传入的存储桶策略限制对S3内容的访问时 Referer: 标题,你需要做一些自定义配置来“智取”CloudFront。

重要的是要了解CloudFront旨在成为一个行为良好的缓存。通过“乖巧”,我的意思是CloudFront旨在永远不会返回与原始服务器返回的响应不同的响应。我相信你可以看到这是一个重要因素。

假设我在CloudFront后面有一个Web服务器(而不是S3),我的网站设计为根据检查结果返回不同的内容 Referer: header ...或任何其他http请求标头,例如 User-Agent: 例如。根据您的浏览器,我可能会返回不同的内容。 CloudFront如何知道这一点,以避免为用户提供某个页面的错误版本?

答案是,它无法分辨 - 它无法知道这一点。因此,CloudFront的解决方案根本不是将大多数请求标头转发到我的服务器。我的Web服务器无法看到它,它无法做出反应,因此我返回的内容不会因我没有收到的标头而有所不同,这会阻止CloudFront缓存并根据这些标头返回错误的响应。 Web缓存有义务避免为给定页面返回错误的缓存内容。

“但是等等,”你反对。 “我的网站取决于某个标题的值,以确定如何回应。”是的,这很有道理......所以我们必须告诉CloudFront:

我没有根据请求的路径缓存我的页面,而是需要你转发 Referer: 要么 User-Agent: 或浏览器发送的其他几个标题之一, 并缓存响应以用于其他请求,这些请求不仅包括相同的路径,还包含您转发给我的额外标头的相同值

但是,当源服务器是S3时,CloudFront不支持转发大多数请求标头,假设由于静态内容不太可能发生变化,这些标头只会导致它不必要地缓存多个相同的响应。

您的解决方案不是告诉CloudFront您使用S3作为原点。而是将您的发行版配置为使用“自定义”源,并为其指定要用作源服务器主机名的存储区的主机名。

然后,您可以配置CloudFront以转发 Referer: 标头到源,并且基于该标头拒绝/允许请求的S3存储桶策略将按预期工作。

好吧,几乎和预期的一样。这会稍微降低缓存命中率,因为现在缓存页面将根据路径+引用页面进行缓存。如果一个S3对象被多个站点的页面引用,CloudFront将为每个唯一请求缓存一个副本。这听起来像是一个限制,但实际上,它只是一个正确缓存行为的工件 - 无论转发到后端的几乎全部,都必须用于确定该特定响应是否可用于为将来的请求提供服务。

看到 http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/distribution-web-values-specify.html#DownloadDistValuesForwardHeaders 用于将CloudFront配置为将特定标头列入白名单以发送到源服务器。

重要提示:请勿转发任何不需要的标头,因为每个变体请求都会进一步降低您的命中率。特别是当使用S3作为自定义原点的后端时,请不要转发 Host: 标题,因为这可能不会达到您的预期。选择 Referer: 标题在这里,并测试。 S3应该开始看到标题并做出相应的反应。

请注意,当您删除存储桶策略以进行测试时,除非您通过发送无效请求来刷新缓存,否则CloudFront将继续提供缓存错误页面,这会导致CloudFront清除所有与您指定的路径模式匹配的缓存页面约15分钟。在试验时最简单的方法是使用新配置创建新的CloudFront分配,因为分发本身不收取任何费用。

从CloudFront查看响应标头时,请注意 X-Cache: (命中/错过)和 Age: (多久以前这个特定的页面被缓存)响应。这些在故障排除中也很有用。


更新:  @alexjs 已经做了一个重要的观察:而不是使用桶策略并转发 Referer: 标题为S3进行分析 - 这会影响您的缓存比率,其范围随着资源在引用页面上的传播而变化 - 您可以使用新的AWS Web应用程序防火墙服务,该服务允许您对传入的请求实施过滤规则CloudFront,允许或阻止基于的请求 请求标头中的字符串匹配

为此,您需要将分发连接到S3,如S3源(正常配置,与我提出的相反,在上面的解决方案中,使用“自定义”原点)并使用CloudFront的内置功能验证对S3的后端请求(因此如果恶意行为者直接向S3请求,则不能直接访问存储桶内容)。

看到 https://www.alexjs.eu/preventing-hotlinking-using-cloudfront-waf-and-referer-checking/ 有关此选项的更多信息。


10
2018-01-20 11:30





此外,它可能是简单的事情。当您首次将文件上载到S3存储桶时,即使该存储桶中的其他文件是公共的,即使存储桶本身是公共的,它也是非公开的。

要在AWS控制台中更改此项,请选中要公开的文件夹旁边的框(刚刚上传的文件夹),然后从菜单中选择“公开”。

该文件夹(和任何子文件夹)中的文件将公开,您将能够从S3提供文件。

对于AWS CLI,在命令中添加“--acl public-read”选项,如下所示:

aws s3 cp index.html s3://your.remote.bucket --acl public-read

3
2017-11-23 05:21



使用cloudfront访问S3时,您应该使用原始访问ID,而不是将S3存储桶暴露给公众。然后,存储桶可以授予存储桶策略的权限(如果使用控制台设置云端,则实际上可以自动完成)。 - Efren