如何限制AWS S3文件仅允许Cognito用户或访客查看而无法下载
实现S3文件仅可查看播放、禁止下载的完整方案
以下为适配认证/未认证用户访问的全流程实操指导,全程无额外外部依赖:
1 核心架构逻辑
整套方案以CloudFront为统一接入层,S3设为私有源站仅允许CloudFront访问,Cognito做身份校验,Lambda@Edge实现权限控制和下载限制,所有资源访问路径不暴露S3直链。
2 分步实现步骤
2.1 第一步:配置S3存储桶基础规则
- 关闭存储桶全部公共访问权限,仅通过CloudFront源访问控制(OAC)授予访问权限,禁止任何S3直链访问
- 存储桶策略参考配置:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "cloudfront.amazonaws.com" }, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::你的存储桶名称/*", "Condition": { "StringEquals": { "AWS:SourceArn": "arn:aws:cloudfront::你的AWS账号ID:distribution/你的CloudFront分发ID" } } } ] }
- 不需要开启S3静态网站托管,直接用CloudFront对接S3标准源站即可。
2.2 第二步:配置Cognito身份池(兼容认证+未认证用户)
- 创建Cognito身份池,勾选启用未认证身份访问,保证未登录访客也能拿到临时访问权限
- 身份池对应的认证、未认证IAM角色,仅授予
AmazonCognitoReadOnly最小权限,不要配置S3直接访问权限 - 前端侧完成Cognito身份校验后,将拿到的JWT令牌放在
Authorization请求头中访问CloudFront资源。
2.3 第三步:配置Lambda@Edge函数(核心控制逻辑)
需要部署2个Lambda@Edge(必须部署在us-east-1区域),分别绑定到CloudFront的不同触发事件:
2.3.1 查看请求触发器(Viewer Request)
用于校验请求身份合法性,拦截非法请求,认证/未认证合法用户全部放行:
// Node.js运行时 exports.handler = (event, context, callback) => { const request = event.Records[0].cf.request; const authHeader = request.headers.authorization?.[0]?.value; // 此处补充Cognito JWT校验逻辑,无效令牌按未认证用户处理,恶意请求直接返回403 // 合法的认证/未认证用户都放行 callback(null, request); };
2.3.2 源响应触发器(Origin Response)
用于修改响应头,强制浏览器内联打开资源,禁止触发下载行为:
exports.handler = (event, context, callback) => { const response = event.Records[0].cf.response; const headers = response.headers; // 核心配置:强制内联打开,不触发下载弹窗 headers['content-disposition'] = [{key: 'Content-Disposition', value: 'inline'}]; // 可选配置:禁止资源缓存,避免链接被分享复用 headers['cache-control'] = [{key: 'Cache-Control', value: 'no-store, must-revalidate'}]; callback(null, response); };
注意:Lambda@Edge的执行角色需要添加lambda.amazonaws.com和edgelambda.amazonaws.com两个服务主体到信任关系中。
2.4 第四步:CloudFront分发配置
- 源站选择目标S3桶,启用OAC关联之前创建的源访问控制
- 行为配置:默认行为绑定上述两个Lambda@Edge触发器,允许的HTTP方法仅保留
GET、HEAD,禁用所有修改类方法 - 可选配置:启用CloudFront签名URL/签名Cookie,设置资源链接有效期,避免链接被外传滥用。
2.5 CloudFormation栈部署参考
可直接使用以下模板片段组合成完整部署栈,替换对应参数即可:
AWSTemplateFormatVersion: '2010-09-09' Parameters: BucketName: Type: String CognitoIdentityPoolId: Type: String Resources: # S3存储桶配置 S3Bucket: Type: AWS::S3::Bucket Properties: BucketName: !Ref BucketName PublicAccessBlockConfiguration: BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true # CloudFront OAC配置 CloudFrontOAC: Type: AWS::CloudFront::OriginAccessControl Properties: OriginAccessControlConfig: Name: !Sub ${BucketName}-oac OriginAccessControlOriginType: s3 SigningBehavior: always SigningProtocol: sigv4 # 其余CloudFront分发、Lambda@Edge、Cognito角色配置按上述规则补充即可
注意:CloudFormation中部署Lambda@Edge时需要指定AutoPublishAlias: live,再关联CloudFront触发事件。
3 注意事项
- 没有绝对的防下载方案:只要用户可以正常在线查看/播放资源,就可以通过抓包、浏览器插件等方式提取资源,上述配置仅能阻止普通用户的直接下载行为,对高安全要求的场景需要额外添加DRM加密、动态水印等防护措施
- Lambda@Edge日志会输出到对应边缘节点所在区域的CloudWatch日志组,排查问题时需要切换到对应区域查看
- CloudFormation部署Lambda@Edge时如果提示跨区域权限错误,优先检查Lambda执行角色的信任关系配置是否正确。
内容的提问来源于stack exchange,提问作者sameerawsnoob
相关产品推荐
相关产品推荐

