为CloudFront分发的公开S3对象配置CORS并限制指定域名访问
解决CloudFront+S3仅允许指定域名访问的问题
核心问题分析
你当前的问题根源在于:S3存储桶被设为公开后,任何不带Origin头的直接请求(包括非浏览器发起的请求)都能获取对象,而S3的CORS策略只负责校验浏览器的跨域请求,无法拦截这类直接访问。同时当前CloudFront配置没有对请求来源做限制,导致非指定域名也能访问。
可行解决步骤
1. 收回S3存储桶的公开权限
首先要确保只有CloudFront能访问S3对象,取消公开权限:
- 进入S3存储桶的权限选项卡,开启“阻止所有公开访问”(仅保留CloudFront的访问权限)
- 添加存储桶策略,只允许CloudFront的源访问身份(OAI)读取对象:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity [你的OAI ID]" }, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::[你的存储桶名称]/*" } ] }
注:需先为CloudFront创建Origin Access Identity(OAI),并在分发的源设置中关联该OAI
2. 在CloudFront层限制请求来源
方案A:用CloudFront函数校验请求头
创建一个查看器请求触发的CloudFront函数,校验Origin或Referer头,非指定域名直接返回403:
function handler(event) { const request = event.request; const allowedDomain = "https://www.example.com"; const origin = request.headers.origin?.value; const referer = request.headers.referer?.value; // 校验跨域请求的Origin头 if (origin && origin !== allowedDomain) { return { statusCode: 403, statusDescription: "Forbidden" }; } // 校验直接访问的Referer头 if (!origin && (!referer || !referer.startsWith(allowedDomain))) { return { statusCode: 403, statusDescription: "Forbidden" }; } return request; }
将该函数绑定到CloudFront分发的对应行为上。
方案B:用AWS WAF规则拦截非法请求
给CloudFront关联AWS WAF,创建两条规则:
- 规则1:匹配
Origin头等于https://www.example.com,动作为“允许” - 规则2:匹配
Referer头包含https://www.example.com,动作为“允许”
设置默认动作为“阻止”,拦截所有未匹配的请求。
3. 保留原S3 CORS策略
原有的CORS策略无需修改,它会继续负责浏览器跨域请求的合法性校验。
验证方式
- 用指定域名
https://www.example.com发起请求,确认正常访问 - 用其他域名或直接输入CloudFront URL,确认返回403
- 用curl发起不带
Origin和Referer的请求,确认返回403
内容的提问来源于stack exchange,提问作者cswamy
相关产品推荐
相关产品推荐

