
CloudFlare R2 是大善人推出的重磅免费服务,默认即为用户提供 10G 存储空间和无限流量。不过这个无限还是有限制的,即每月写入类操作不超过 100 万次,每月读取类操作不能超过 1000万次,否则就将按量计费。最近我搬迁了 11 万多张图片到 R2 ,有点担心使用超限,所以对其作了严格的防护设置。
防护原理
我需要设置防护的这个 R2 存储桶是此前在
<a class="link" href="https://lawtee.com/article/trans-soomal-to-hugo/" rel="noopener"
将Soomal.cc迁移到Hugo
这篇文章中提到的
soomal.cc 网站中的图片。
该网站已经托管在 Cloudflare Pages ,由 Cloudflare Pages 提供免费服务,只需要对 html 中引用的图片进行防护。
1.
限制直接对R2存储桶访问。禁止使用链接直接访问 R2 存储桶,而是只能通过 Cloudflare Workers 服务进行访问。
2.
限制对图库链接的直接访问。禁止直接使用
https://images.soomal.cc/test.webp 这种网址请求图片,对所有图片的访问均需在原网站下进行。
3.
对原站启用适当防护策略。由于图片本身不适合设置太多防护规则,主要是通过在原站上设置,变相增加直接请求图片链接的难度。
设置方法
禁用 R2 公开地址
在 R2 设置中,不要设置自定义域访问,不要在网络上公开 R2。
在 Cors 策略中,设置仅通过原站访问。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
[
{
"AllowedOrigins": [
"https://soomal.cc",
"https://www.soomal.cc"
],
"AllowedMethods": [
"GET",
"HEAD"
],
"AllowedHeaders": [
"*"
],
"ExposeHeaders": [
"ETag"
],
"MaxAgeSeconds": 3600
}
]
|
添加 Workers 访问规则
- 创建一个 Worker。
- 绑定 R2 存储桶。
- 添加自定义域和路由。
- 添加 Workers代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request));
});
async function handleRequest(request) {
const url = new URL(request.url);
const referer = request.headers.get('referer');
const allowedDomains = ['soomal.cc', 'www.soomal.cc'];
// 处理 images.soomal.cc 的图片请求
if (url.host === 'images.soomal.cc') {
if (referer && allowedDomains.some(domain => referer.includes(domain))) {
const filePath = url.pathname.replace(/^\//, '');
try {
const object = await R2.get(filePath);
if (object === null) {
console.log(`File not found: ${filePath}`);
return new Response('File Not Found', {
status: 404,
headers: { 'Content-Type': 'text/plain' }
});
}
const headers = new Headers();
headers.set('Content-Type', object.httpMetadata.contentType || 'image/webp');
headers.set('Cache-Control', 'public, max-age=31536000');
headers.set('Access-Control-Allow-Origin', 'https://soomal.cc');
return new Response(object.body, { status: 200, headers });
} catch (error) {
console.log(`Error: ${error.message}`);
return new Response('Internal Server Error', {
status: 500,
headers: { 'Content-Type': 'text/plain' }
});
}
}
console.log(`Unauthorized: Referer ${referer} not allowed`);
return new Response('Unauthorized Access', {
status: 403,
headers: { 'Content-Type': 'text/plain', 'Cache-Control': 'no-store, no-cache' }
});
}
// 如果主机名不是 images.soomal.cc 或 www.soomal.cc,直接返回 404
return new Response('Not Found', {
status: 404,
headers: { 'Content-Type': 'text/plain' }
});
}
|
这个脚本主要作用是将所有包含 images.soomal.cc 的请求,都通过 Workers 去访问。
利用 Workers 每天 10 万次的限额(30天就是300万次),确保对 R2 存储桶的访问数不会爆单。
其实设置到这里,我的目的也就达到了。因为每天 10万次访问,已经足够这个备份网站使用。一旦超额,workers 直接罢工,图片也就无法访问了。
添加必要的防护策略(可选)
经过上边设置后,所有对 R2 存储桶的请求,都只能通过原站
soomal.cc 访问。
这样,就可以继续通过对原站添加必要防护,变相提升对图片的防护能力。
- 启用SSL严格模式。
- 启用缓存。建议是能缓存的全缓存。
- 安全规则。可以启用连续脚本监视、浏览器完整性检查、速率限制、自动程序攻击模式等功能,进一步增加防护。