大意失荆州 — 浅谈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边缘测部署生效了,网站可以就可以正常访问了。

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

添加评论
点赞收藏
点踩分享查看原文
评论
?
参与讨论