You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

私有S3桶+Cloudfront Signed Url架构下,如何限制仅门户域名访问?

解决CloudFront+私有S3场景下Referer策略不稳定的问题

核心原因

你遇到的时好时坏问题,本质是CloudFront缓存机制导致的:当请求命中CloudFront缓存时,请求不会转发到S3,此时S3的Referer策略完全不生效;只有未命中缓存的请求才会触发S3的校验,所以出现部分文件有效、部分无效的情况。

解决方案

1. 将Referer校验移到CloudFront层(推荐方案)

让所有请求(无论是否命中缓存)都先经过CloudFront的校验,彻底避免绕过S3策略的情况,有两种实现方式:

方式一:使用Lambda@Edge(Viewer Request触发器)

创建一个Viewer Request阶段的Lambda函数,在请求进入CloudFront时直接校验Referer头,不符合则返回403:

exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;
    const headers = request.headers;
    
    // 替换为你的门户域名列表
    const allowedDomains = ['www.example.com', 'example.com'];
    const referer = headers.referer ? headers.referer[0].value : '';
    let isAllowed = false;

    if (referer) {
        try {
            const refererHost = new URL(referer).hostname;
            isAllowed = allowedDomains.includes(refererHost);
        } catch (e) {
            // 无效Referer格式,直接拒绝
            isAllowed = false;
        }
    }

    if (!isAllowed) {
        const response = {
            status: '403',
            statusDescription: 'Forbidden',
            body: {
                content: '访问被拒绝:无效来源',
                contentEncoding: 'UTF-8',
                contentType: 'text/html'
            }
        };
        callback(null, response);
    } else {
        callback(null, request);
    }
};

将该函数部署到CloudFront分发的Viewer Request触发器,所有请求都会先经过这个校验。

方式二:配置CloudFront Origin请求策略(配合S3策略)

如果仍需要S3层的校验,必须确保CloudFront会把Referer头传递给S3:

  • 创建Origin请求策略,添加Referer到转发的头部列表
  • 将该策略关联到CloudFront的分发行为
  • 同时调整CloudFront缓存策略,避免不同Referer的请求共享缓存(比如把Referer加入缓存键)

2. 修正S3 Bucket Policy的问题

你的现有策略存在两个关键错误:

  • Resource字段格式错误:"arn:aws:s3:::/*"需替换为你的Bucket全称,比如"arn:aws:s3:::your-bucket-name/*"
  • 缺少兜底的Deny策略:仅靠Allow策略无法覆盖所有场景,需显式拒绝不符合条件的请求

修正后的Bucket Policy示例:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowValidRefererViaCloudFront",
            "Effect": "Allow",
            // 建议替换为CloudFront的OAI,而非*,进一步限制访问来源
            "Principal": {"AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity YOUR-OAI-ID"},
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::your-bucket-name/*",
            "Condition": {
                "StringLike": {
                    "aws:Referer": [
                        "https://www.example.com/*",
                        "https://example.com/*"
                    ]
                }
            }
        },
        {
            "Sid": "DenyInvalidReferer",
            "Effect": "Deny",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::your-bucket-name/*",
            "Condition": {
                "StringNotLike": {
                    "aws:Referer": [
                        "https://www.example.com/*",
                        "https://example.com/*"
                    ]
                }
            }
        }
    ]
}

3. 启用CloudFront Origin Access Identity(OAI)

必须确保只有CloudFront能直接访问S3,杜绝绕过CloudFront直接访问S3的可能:

  • 在CloudFront分发中创建并关联OAI
  • 在S3 Bucket Policy中仅允许该OAI的GetObject权限
  • 关闭S3 Bucket的所有公共访问设置

额外防护建议

  • Referer头可被伪造,若需更强防护,可结合CloudFront Signed Cookies+Lambda@Edge校验门户的用户会话(比如验证登录状态Cookie)
  • 确保门户使用HTTPS,避免Referer头被明文传输或篡改
  • 测试时可临时禁用CloudFront缓存,验证策略逻辑是否正确,再逐步开启缓存

内容的提问来源于stack exchange,提问作者Mozzak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 18:26:10