使用 S3 和 CloudFront 防止图像盗链

Prevent image hotlinking with S3 and CloudFront

我有一个有很多页面的网站,每个页面都有很多图片(几十张甚至几百张)。

我正在努力避免图像盗链,但又不会过多增加 AWS 成本。

到目前为止,我找到了 3 个选项:

选项 1:使用 WAF 来防止盗链,通过创建一个基于 referer 的规则来阻止 header。

https://aws.amazon.com/pt/blogs/security/how-to-prevent-hotlinking-by-using-aws-waf-amazon-cloudfront-and-referer-checking/

这个解决方案的问题是,如果你在每个页面上加载很多图片,成本会增加太多,因为除了支付 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”选项: