我正在处理视频应用并将文件存储在AWS S3上,使用403 (Forbidden)
之类的默认网址正常但我决定使用CloudFront,这样可以更快地进行内容传送。
使用CF,我不断使用此网址https://***.cloudfront.net/***
获取SELECT * FROM CONTAINSTABLE(data,*,'("Linker*" OR "pagina*") AND NOT ( "pagina*" AND "Linker*")') AS Results
。我错过了什么吗?
在我决定从CloudFront加载指向我的存储桶的内容之前,一切正常。
有任何解决方案吗?
答案 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权限,请使用此文档手动添加权限
还要确保您已在s3和cloudfront中指定了入口点(在我的情况下为index.html)
我尚未在Cloudfront中创建任何错误页面,希望它可以节省一些人的时间
编辑:重新加载页面时抛出403错误,因此我为403和404添加了错误页面,并且在cloudfront中将页面添加为“ /index.html”
答案 5 :(得分:0)