AWS S3:当aws:Referer可被伪造时,如何确保资源仅网站可访问?
确保S3资源仅通过EC2部署的网站访问的可靠方案
你提到的Referer策略确实存在伪造风险,要实现真正的访问控制,以下是几个生产环境常用的可靠方案,按推荐优先级排序:
方案一:EC2代理S3请求(最安全)
将S3桶设置为完全私有,仅允许EC2实例的IAM角色访问S3资源,用户通过EC2网站间接获取S3内容:
- 步骤1:创建IAM角色,为其添加仅允许访问目标S3桶的权限策略,示例:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["s3:GetObject", "s3:GetObjectVersion"], "Resource": "arn:aws:s3:::DOC-EXAMPLE-BUCKET/*" } ] }
- 步骤2:将该IAM角色关联到你的EC2实例,确保EC2无需硬编码凭证即可访问S3。
- 步骤3:修改网站后端逻辑,当用户请求S3资源时,由EC2后端从S3获取资源,再返回给用户。
这种方式下,S3桶完全不对外暴露,所有访问必须经过你的EC2网站,彻底杜绝未授权访问。
方案二:使用S3预签名URL
S3预签名URL由拥有S3访问权限的实体(你的EC2实例角色)生成,带有有效期,用户只能通过该URL访问指定资源:
- 步骤1:同样给EC2实例分配具备S3 GetObject权限的IAM角色(同方案一的角色策略)。
- 步骤2:在网站后端,当用户需要访问S3资源时,使用AWS SDK生成预签名URL,示例(Python):
import boto3 from botocore.config import Config s3 = boto3.client('s3', config=Config(signature_version='s3v4')) presigned_url = s3.generate_presigned_url( 'get_object', Params={'Bucket': 'DOC-EXAMPLE-BUCKET', 'Key': 'your-object-key'}, ExpiresIn=3600 # URL有效期1小时 )
- 步骤3:将生成的预签名URL返回给前端,用户通过该URL直接访问S3。
即使预签名URL被泄露,过期后也无法使用,且只有你的EC2网站能生成有效URL,保证了访问的可控性。
方案三:CloudFront + Origin Access Control(OAC)+ 签名URL/Cookie
如果需要CDN加速S3资源,可配合CloudFront实现更高效且安全的访问控制:
- 步骤1:创建CloudFront分发,将目标S3桶设为源,启用Origin Access Control(OAC),确保只有CloudFront能访问S3桶(更新S3桶策略,仅允许OAC的服务主体访问)。
- 步骤2:为CloudFront配置签名URL或签名Cookie,由你的EC2网站后端生成签名(需要CloudFront密钥对)。
- 步骤3:用户访问EC2网站时,获取签名URL/Cookie,通过CloudFront访问S3资源。
这种方式结合了CDN的性能优势,同时通过签名机制确保只有你的网站能授权用户访问S3资源。
注意事项
- 无论采用哪种方案,务必确保S3桶的公共访问设置完全关闭(在S3控制台的「权限」-「阻止公共访问」中开启所有选项)。
- 避免在EC2实例中硬编码AWS凭证,始终使用IAM实例角色进行权限管理。
内容的提问来源于stack exchange,提问作者AG_HIHI
相关产品推荐
相关产品推荐

