大意失荆州 — 浅谈cdn后面的源站防护

随着开发的服务和应用越来越多,当初为了省事直接通过后端提供服务的做法,从短期看来的确是省了再次部署的麻烦。但是,这种做法也挖了一些深坑,并且,这些坑不见得什么时候就成了拖垮系统的罪魁祸首。
当初为了省事,很多服务直接通过端口映射之后就作为后端服务发布了。

当然,并不是直接暴露后端真实服务器的地址,前面还套了一层eo。想着最前面是eo,默认请求都会经过eo转发,本身图片等相关资源都有cdn缓存也不会打到服务器上,只有cdn边缘服务器第一次请求的时候会访问真正的后台文件,这样原来,直接通过后端服务提供静态资源访问也是足够的,并且跑了这么长时间也没什么问题。但是,事实并非总是这么可靠。
昨天 你来啦 发版之后,想着填写一下appstore的下载地址,结果登录后台直接提示502了。
登录服务器看了一下,后台服务进程被大量下载直接拖死了:
22.79.117.157:55212 - - [13/Oct/2026:16:26:03] "GET /media/packages/2026/10/__UNI__8813F79_1007202252.apk" 200 79556639 113.219.202.124:5113 - - [13/Oct/2026:16:26:03] "GET /media/packages/2026/10/__UNI__8813F79_1007202252.apk" 200 79556639 113.219.202.2:12879 - - [13/Oct/2026:16:26:04] "GET /media/packages/2026/10/__UNI__8813F79_1007202252.apk" 200 79556639 113.219.202.3:46581 - - [13/Oct/2026:16:26:04] "GET /media/packages/2026/10/__UNI__8813F79_1007202252.apk" 200 79556639 222.79.116.209:27848 - - [13/Oct/2026:16:26:04] "GET /media/packages/2026/10/__UNI__8813F79_1007202252.apk" 200 79556639 222.79.116.184:59270 - - [13/Oct/2026:16:26:04] "GET /media/packages/2026/10/__UNI__8813F79_1007202252.apk" 200 79556639 2026-10-13 16:26:25,486 WARNING Application instance wait_for=> for connection took too long to shut down and was killed. 2026-10-13 16:26:25,542 WARNING Application instance wait_for=> for connection took too long to shut down and was killed. 2026-10-13 16:26:25,543 WARNING Application instance wait_for=> for connection took too long to shut down and was killed. 2026-10-13 16:26:25,543 WARNING Application instance wait_for=> for connection took too long to shut down and was killed. 2026-10-13 16:26:25,543 WARNING Application instance wait_for=> for connection took too long to shut down and was killed. 2026-10-13 16:26:25,548 WARNING Application instance wait_for=> for connection took too long to shut down and was killed. 2026-10-13 16:26:25,548 WARNING Application instance wait_for=._outer_done_callback() at /usr/lib/python3.10/asyncio/tasks.py:864, Task.task_wakeup()]>> for connection took too long to shut down and
这一堆请求__UNI__8813F79_1007202252.apk的访问,几乎是在同一秒内发出的,并且这些ip也不是eo的cdn边缘服务器ip,那么就只有一种可能,就是源服务器的地址暴露了,被别有用心的的人用来洗白流量了。这种大文件请求,也是pcdn常用的技俩,正好服务器还有大资源文件,带宽又够,的确是个不错的软柿子。
鉴于在这种情况下,要解决这个问题也简单,那就是直接屏蔽掉除了eo节点之外的所有的直接流量,此时只需要找到eo的服务器列表,添加到安全组或者防护策略或者nginx的配置文件中即可,然鹅,eo免费版本并不具备此功能:

那么,应该怎么办?就只能坐以待毙吗?当然,可以通过解析加速域名的dns解析获取所有的边缘测地址:

只是这种做法难免有些不入流。
这就黔驴技穷了?那肯定不可能,想姐姐我是何种人物,没了张屠夫还非得吃带毛的的?
基于边缘测的请求改写,给所有的请求添加一个自定义头,在源服务器检测就可以解决这个问题了。
边缘测:

服务器配置:
如果是openresty,直接写到nginx.conf 的http部分即可:
# 只放行 CDN 回源。直连源站(IP 或绕过 CDN)没有该头,返回 403,不读盘、不进 Daphne。
# CDN 需在回源请求上添加:baby-fuck-playboys: baby-fuck-all-invalid-requests
# rewrite 的 if 只能写在 server/location,放进 http 段会 nginx -t 失败,也盖不住各 vhost。
# access 阶段对所有 server / location 生效,先于静态文件、FastCGI、反代。
access_by_lua_block {
if ngx.var.http_baby_fuck_playboys ~= "baby-fuck-all-invalid-requests" then
return ngx.exit(403)
end
}如果是nginx 需要在每个server下面单独进行配置,当然也可以写成一个统一的配置文件,在需要启用检测的地方直接include即可。
# 只放行 CDN 回源。直连源站(IP 或绕过 CDN)没有该头,返回 403,不读盘、不进 Daphne。
# CDN 需在回源请求上添加:baby-fuck-playboys: baby-fuck-all-invalid-requests
if ($http_baby_fuck_playboys != "baby-fuck-all-invalid-requests") {
return 403;
}配置好之后重启openresty 或者nginx,此时没有合法请求头的访问就直接403了:

小技巧:如何修改postman的host,正常情况这个东西是不让修改的,显示calculated when request is send。那么,取消掉原来的默认host,在下面新建一个,填写自己想要使用的host就可以了。
等eo边缘测部署生效了,网站可以就可以正常访问了。

当然,前提是别改漏了。域名实在是太多了,有两个就给忘了:
