如何让Next.js <Image>标签与AWS S3存储桶策略兼容?
问题:Next.js + Vercel + AWS S3 图片访问限制问题
我将Next.js应用部署在Vercel平台,使用AWS S3存储桶存储图片,希望仅允许我的网站读取这些图片。CORS策略已设置为允许所有流量:
[ { "AllowedHeaders": [ "*" ], "AllowedMethods": [ "GET", "POST", "PUT", "DELETE" ], "AllowedOrigins": [ "*" ], "ExposeHeaders": [], "MaxAgeSeconds": 3000 } ]
对应的存储桶策略为:
{ "Sid": "AllowReadFromWebsite", "Effect": "Allow", "Principal": "*", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::my-bucket/*", "Condition": { "StringLike": { "aws:Referer": [ "https://my-domain.vercel.app/*", "https://my-domain.vercel.app/_next/image*" ] } } }
该策略在生产环境中无法与Next.js <Image>标签配合使用,但普通<img>标签可正常工作。开发环境中,将http://localhost:3000添加到存储桶策略后,两种标签都能正常运行。我怀疑请求并非直接来自我的网站域名,可能与服务器或缓存有关,不确定问题出在Next.js Image标签、Vercel还是无服务器架构。
目前暂用允许任意读取的策略:
{ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowReadFromAnywhere", "Effect": "Allow", "Principal": "*", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::my-bucket/*" } ] }
这种做法是否不妥?我不太在意安全性,只是不想他人恶意消耗我的带宽。
解决方案
问题根源
Next.js的<Image>组件在生产环境中会通过Vercel的Image Optimization服务处理图片,此时请求S3的来源并非你的网站域名,而是Vercel的优化服务节点,导致aws:Referer条件不匹配,被存储桶策略拒绝。
修正后的存储桶策略
需要将Vercel图片优化服务的请求特征加入允许列表,修正后的策略示例:
{ "Sid": "AllowReadFromWebsiteAndVercelOptimization", "Effect": "Allow", "Principal": "*", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::my-bucket/*", "Condition": { "StringLike": { "aws:Referer": [ "https://my-domain.vercel.app/*", "https://*.vercel.app/_next/image*" ] } } }
虽然Referer头可以被伪造,但对于防范普通盗链、减少带宽滥用已经足够。
关于临时策略的问题
当前允许任意读取的策略确实存在风险,他人可直接盗链你的S3图片URL,或批量爬取资源,导致你的S3流量费用大幅上升,建议尽快替换为限制来源的策略。
内容的提问来源于stack exchange,提问作者Cole
相关产品推荐
相关产品推荐

