使用 S3 和 CloudFront 防止图像盗链
Prevent image hotlinking with S3 and CloudFront
我有一个有很多页面的网站,每个页面都有很多图片(几十张甚至几百张)。
我正在努力避免图像盗链,但又不会过多增加 AWS 成本。
到目前为止,我找到了 3 个选项:
选项 1:使用 WAF 来防止盗链,通过创建一个基于 referer 的规则来阻止 header。
这个解决方案的问题是,如果你在每个页面上加载很多图片,成本会增加太多,因为除了支付 S3 和 CloudFront,你还需要支付 WAF,每个 个图像请求(例如,想象一下如果您在每个页面上有 100 张图像)。
选项 2:配置 CloudFront 以触发 Lambda@Edge Viewer 请求触发器,该触发器将在每个请求进入前门时对其进行检查,并根据引用 header 阻止请求。
这与上面的选项类似。问题是您向 EVERY 请求添加了开销,即使图像已经在 CloudFront 缓存中也是如此。 Lambda@Edge 将始终被调用,并且如果您的网站的每个页面上有很多图像,也会增加太多成本。
选项 3:配置 S3 存储桶策略以根据引用 header 阻止请求,并在 CloudFront 将引用 header 列入白名单。
到目前为止,这在我看来是成本效益最高的选项,因为如果图像已经在 CloudFront 缓存中,您没有任何开销,而且成本也是最低的,因为您不这样做无需支付 WAF 或 Lambda@Edge。
问题是缓存命中率会小很多,因为除非传入请求的 Referer header 完全 匹配,否则 CloudFront 不会提供来自缓存的响应来自 already-cached 请求。
我尝试使用“来源”请求 header 来避免这个问题,但浏览器似乎不会为图像 GET 请求发送此 header。
还有更好的选择吗?
您可以通过使用 CloudFront 支持的本机选项来避免上述情况,Signed Cookies。
如果用户登陆非基于资产的页面(即主页),通过添加 Lambda@Edge function,您可以生成签名 cookie。通过在 CloudFront 中强制执行此操作,只有浏览您网站的人才能访问资产。
或者您可以生成一个 CloudFront signed URL,但需要为每个资产完成此操作。
要使用这些为您要保护的资产创建次要来源/行为并添加 Restrict Viewer Access (Use Signed URLs or Signed Cookies)
的行为规则。 Lambda@Edge 将存在于另一个来源。
我最终使用了选项 3(S3 存储桶策略)并且另外使用了 CloudFlare 的免费计划。即使在免费计划中,CloudFlare 在“Scrape Shield”中也有“Hotlink Protection”。
防止盗链的S3存储桶策略:
{
"Version": "2012-10-17",
"Id": "http referer policy",
"Statement": [
{
"Sid": "Allow access only from my website",
"Effect": "Deny",
"Principal": {
"AWS": "*"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::resources.mywebsite.com/*",
"Condition": {
"StringNotLike": {
"aws:Referer": [
"https://dev.mywebsite.com:8080/*",
"https://staging.mywebsite.com/*",
"https://www.mywebsite.com/*"
]
}
}
}
]
}
在 CloudFront 中,我将 Referer 列入白名单 header:
并且在 CloudFlare 中,您可以在“Scrape Shield”菜单中启用“Hotlink Protection”选项:
我有一个有很多页面的网站,每个页面都有很多图片(几十张甚至几百张)。
我正在努力避免图像盗链,但又不会过多增加 AWS 成本。
到目前为止,我找到了 3 个选项:
选项 1:使用 WAF 来防止盗链,通过创建一个基于 referer 的规则来阻止 header。
这个解决方案的问题是,如果你在每个页面上加载很多图片,成本会增加太多,因为除了支付 S3 和 CloudFront,你还需要支付 WAF,每个 个图像请求(例如,想象一下如果您在每个页面上有 100 张图像)。
选项 2:配置 CloudFront 以触发 Lambda@Edge Viewer 请求触发器,该触发器将在每个请求进入前门时对其进行检查,并根据引用 header 阻止请求。
这与上面的选项类似。问题是您向 EVERY 请求添加了开销,即使图像已经在 CloudFront 缓存中也是如此。 Lambda@Edge 将始终被调用,并且如果您的网站的每个页面上有很多图像,也会增加太多成本。
选项 3:配置 S3 存储桶策略以根据引用 header 阻止请求,并在 CloudFront 将引用 header 列入白名单。
到目前为止,这在我看来是成本效益最高的选项,因为如果图像已经在 CloudFront 缓存中,您没有任何开销,而且成本也是最低的,因为您不这样做无需支付 WAF 或 Lambda@Edge。
问题是缓存命中率会小很多,因为除非传入请求的 Referer header 完全 匹配,否则 CloudFront 不会提供来自缓存的响应来自 already-cached 请求。
我尝试使用“来源”请求 header 来避免这个问题,但浏览器似乎不会为图像 GET 请求发送此 header。
还有更好的选择吗?
您可以通过使用 CloudFront 支持的本机选项来避免上述情况,Signed Cookies。
如果用户登陆非基于资产的页面(即主页),通过添加 Lambda@Edge function,您可以生成签名 cookie。通过在 CloudFront 中强制执行此操作,只有浏览您网站的人才能访问资产。
或者您可以生成一个 CloudFront signed URL,但需要为每个资产完成此操作。
要使用这些为您要保护的资产创建次要来源/行为并添加 Restrict Viewer Access (Use Signed URLs or Signed Cookies)
的行为规则。 Lambda@Edge 将存在于另一个来源。
我最终使用了选项 3(S3 存储桶策略)并且另外使用了 CloudFlare 的免费计划。即使在免费计划中,CloudFlare 在“Scrape Shield”中也有“Hotlink Protection”。
防止盗链的S3存储桶策略:
{
"Version": "2012-10-17",
"Id": "http referer policy",
"Statement": [
{
"Sid": "Allow access only from my website",
"Effect": "Deny",
"Principal": {
"AWS": "*"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::resources.mywebsite.com/*",
"Condition": {
"StringNotLike": {
"aws:Referer": [
"https://dev.mywebsite.com:8080/*",
"https://staging.mywebsite.com/*",
"https://www.mywebsite.com/*"
]
}
}
}
]
}
在 CloudFront 中,我将 Referer 列入白名单 header:
并且在 CloudFlare 中,您可以在“Scrape Shield”菜单中启用“Hotlink Protection”选项: