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

时间:2016-01-19 16:36:05

标签: amazon-web-services amazon-s3 amazon-cloudfront

我正在处理视频应用并将文件存储在AWS S3上,使用403 (Forbidden)之类的默认网址正常但我决定使用CloudFront,这样可以更快地进行内容传送。

使用CF,我不断使用此网址https://***.cloudfront.net/***获取SELECT * FROM CONTAINSTABLE(data,*,'("Linker*" OR "pagina*") AND NOT ( "pagina*" AND "Linker*")') AS Results 。我错过了什么吗?

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

有任何解决方案吗?

6 个答案:

答案 0 :(得分:11)

当使用检查传入Referer:标头的存储桶策略来限制对S3内容的访问时,您需要进行一些自定义配置,以便"智能化" CloudFront的。

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

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

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

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

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

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

您的解决方案不是告诉CloudFront您使用S3作为原点。相反,请将您的发行版配置为使用" custom" origin,并为其指定要用作原始服务器主机名的存储桶的主机名。

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

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

有关将CloudFront配置为将特定标头列入白名单以发送到源服务器的信息,请参阅http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/distribution-web-values-specify.html#DownloadDistValuesForwardHeaders

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

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

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

更新 @alexjs做了一个重要的观察:不是使用存储桶策略执行此操作并将Referer:标头转发到S3进行分析 - 这会损害您的缓存比率随着资源在引用页面上的传播而变化 - 您可以使用新的AWS Web应用程序防火墙服务,该服务允许您对来自CloudFront的传入请求强加过滤规则,以允许或阻止基于{{{}的请求。 3}}

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

有关此选项的更多信息,请参阅string matching in request headers

答案 1 :(得分:4)

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

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

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

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

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

答案 2 :(得分:4)

我确定了CloudFront可以返回403 (Bad request)的另一个原因。也许那是一个极端的情况,但我想与您分享。

CloudFront实现了一种前向循环检测机制,可以防止转发循环攻击。
根据AWS支持,您不能将两个以上的CloudFront分布作为原始设备层叠。

假设您已将CloudFront A配置为CloudFront B作为源,从CloudFront B中配置了CloudFront C为源,从CloudFront C将S3存储桶作为源。

A --> B --> C --> S3 bucket (can return a 403 error)

如果您从级联末尾S3存储桶中的CloudFront A请求文件,则CloudFront C将返回403(错误请求)。

如果级联仅由2个CloudFront发行版和最后一个S3存储桶组成,则来自S3原始文件的请求有效。

A --> B --> S3 bucket (works)

答案 3 :(得分:0)

对我来说,我必须授予CodePipeline访问我的S3存储桶策略的权限。例如这样的东西:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::mys3bucket/*"
        }
    ]
}

答案 4 :(得分:0)

我的需求是将存储桶设为私有,所以我使用了OAI,我面临的主要问题是我在发行创建之前创建了OAI,并在源区域下拉列表中选择了它,然后Cloudfront开始抛出403。创建cloudfront源(我从下拉列表中选择了源域名,然后选择了存储桶,然后它提供了限制s3存储桶的选项,然后您将获得创建Origin Access Identity的选项和一个名为“授予存储桶读取权限”的选项,让aws / cloudfront处理)

有时aws可能无法在s3存储桶中添加OAI权限,请使用此文档手动添加权限

https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html#private-content-granting-permissions-to-oai

还要确保您已在s3和cloudfront中指定了入口点(在我的情况下为index.html)

我尚未在Cloudfront中创建任何错误页面,希望它可以节省一些人的时间

编辑:重新加载页面时抛出403错误,因此我为403和404添加了错误页面,并且在cloudfront中将页面添加为“ /index.html”

答案 5 :(得分:0)

我从 cloudfront 收到 POST 请求的 403 错误,其中我的源是域名而不是 s3 存储桶。

原因是 cloudfront 默认不允许 POST。我从控制台中的 POST 选项卡启用了 Behaviors,然后它起作用了。

enter image description here