置顶编程运维
我的博客被攻击了
2026 年 10 年 08 日约 12 分钟森屿
凌晨三点十七分,手机在床头震了一下。是监控群机器人的告警:站点 QPS 从个位数跳到了四百多, 出网带宽打满。我第一反应是某篇文章被转发了,点开一看——请求路径全是不存在的随机字符串。
这不是流量,这是有人在扫。下面把这五个小时的过程完整记下来,包括我踩的坑和最后沉淀出的排查清单。
一、先判断性质,再动手
被打了之后最容易犯的错,是立刻上手封 IP。但如果攻击是分布在大量不同来源上的, 封 IP 只是在跟攻击者赛跑,而且很容易误伤正常用户。所以第一步永远是判断性质,我看了三个指标:
- 请求特征:UA 全部相同,路径无规律,但都命中了一个不存在的动态路由。
- 来源分布:独立 IP 约 2000 个,集中在两个 C 段,不是肉鸡网络,更像单机多线程。
- 目标接口:全部打向那个动态路由,而这个路由会触发一次数据库查询。
结论很明确:这是一次针对性的 CC 攻击,目标是打穿数据库连接池,而不是消耗带宽。
判断性质的本质,是回答「他想让我死在哪里」。防守只有知道了这个,才能把资源放在正确的点上。
二、四层止血
确认性质之后,我按「见效速度」从快到慢做了四件事。
1. 边缘层封禁
在 CDN 上按 UA 特征 + 路径正则直接拦截,这一步十秒钟完成,立刻把流量削掉了九成。
2. 给动态路由加缓存
那个动态路由其实是内容型页面,本身就适合缓存。加了一层边缘缓存之后,请求根本到不了源站。
// next.config.js
async headers() {
return [
{
source: "/posts/:id*",
headers: [
{ key: "Cache-Control", value: "public, s-maxage=3600, stale-while-revalidate=86400" },
],
},
];
}3. 数据库连接池加护栏
设置连接获取超时,并给这个路由单独限流。即便前面的防线被绕过,也不会把连接池拖垮。
4. 补齐监控盲区
这次之所以反应慢了十分钟,是因为告警阈值设得过宽。改成「按路径维度的 QPS 同比增幅」之后, 灵敏度提升了一个数量级。
三、沉淀成清单
下次再遇到,我希望能在三分钟内走完判断流程。所以整理成了这张单子:
- 看总 QPS 与带宽的比值 —— 判断是 CC 还是 DDoS。
- 看 UA / 路径 / IP 三个维度的集中度 —— 判断来源是否单一。
- 看被打的接口是否触达数据库 —— 判断真实目标。
- 边缘先拦,再考虑源站加固 —— 永远从最外层开始。
- 事后必做:把这次的判据写进告警规则。
天亮的时候,站点恢复了正常。攻击者没有攻破任何东西,但它确实拿走了一个东西——我的睡眠。 不过换来的这份清单,我觉得挺值。