从爬虫到生产:一个安全工程师的ML部署踩坑实录
上周五晚上十点半,我戴着降噪耳机听着Lo-fi beats,正准备提交本周最后一个PR时,突然被拉进一个紧急会议——产品那边说要上线一个“智能反爬系统”,用机器学习识别恶意爬虫流量。我当时就懵了:我是来修XSS和越权漏洞的,不是来搞AI的啊!
但没办法,新来的CTO信奉“全栈即正义”,而我这个刚入职俩月的安全工程师,莫名其妙就成了“既懂安全又会写JS”的理想人选。行吧,硬着头皮上。
背景:为什么我们要用ML做反爬?
先说说业务场景。我们公司是个内容平台,每天有数百万真实用户访问,但也有大量爬虫在薅数据——有些是友好的(比如搜索引擎),有些直接暴力请求,把API打到限流,甚至触发服务雪崩。传统的基于User-Agent、IP频率、请求头的规则已经不够用了。黑产现在会模拟浏览器行为、轮换代理IP、伪造Referer,跟打地鼠一样烦人。
于是产品拍板:上机器学习!用算法自动识别异常行为。
我内心OS:这锅真大。但转念一想,其实挺合理——安全本质上就是模式识别。攻击者的行为总有特征,只是人工写规则太滞后。如果能实时提取流量特征,用模型判断是否为恶意爬虫,确实比死板的WAF规则灵活得多。
第一坑:别让模型变成“纸老虎”
刚开始我以为就是训练个模型,丢给后端跑就行。天真了。
我们的数据源来自Nginx日志 + 前端埋点(对,前端也得配合)。每条请求记录包括:
- IP、User-Agent、Referer
- 请求路径、参数、频率
- 是否含Cookie、是否有JS执行痕迹(通过前端埋点上报)
- 是否触发验证码
我用Python快速搭了个Pipeline:Pandas清洗 → Scikit-learn训练 → 模型保存。选了Random Forest,因为可解释性强,方便后续debug。准确率85%,看起来还行。
但问题来了:怎么部署?
后端是Node.js栈,产品经理还特意强调:“不能拖慢接口响应!” 我差点笑出声——你让我在10ms内跑完一个ML推理?除非模型小到能塞进URL里。
于是开始折腾模型瘦身。试过XGBoost(快但依赖复杂)、Logistic Regression(快但效果差)、最后回到Random Forest,但把树的数量砍到20棵,特征从30维压缩到10维。本地测试推理时间压到3ms,勉强过关。
经验教训:模型再准,跑不起来等于零。安全场景尤其如此——延迟太高,用户就骂娘;太低,可能漏报。平衡点在哪?得测!
JavaScript 不是 ML 的禁区
说到部署,很多人觉得JS只配做前端。但Node.js生态其实挺能打。我们最终决定把模型嵌入到Koa中间件里,这样每个请求进来就能实时打分。
但Scikit-learn模型没法直接在JS跑。怎么办?
方案一:用Python起个Flask服务,Node.js调HTTP。
→ 被运维毙了:“多一次网络调用?你知道QPS多少吗?”
方案二:转成PMML或ONNX格式,再用JS解析。
→ 试了onnxruntime-node,结果内存占用爆炸,线上Pod直接OOM。
最后我祭出了终极武器:手写模型预测逻辑。
没错,我把Random Forest的结构导出成JSON,然后用JavaScript重写了预测函数。听起来很疯,但其实可行——树模型本质就是一堆if-else。
// simplified version
function predict(features) {
let score = 0;
for (const tree of model.trees) {
let node = tree.root;
while (!node.isLeaf) {
const featVal = features[node.featureIndex];
node = featVal <= node.threshold ? node.left : node.right;
}
score += node.value;
}
return score / model.trees.length > 0.6 ? 'malicious' : 'normal';
}
代码丑是丑了点,但快、轻、可控。而且因为是我自己写的,加日志、埋点、熔断都方便。上线后CPU占用几乎没涨,运维终于露出了笑容(虽然只持续了5分钟)。
爬虫数据怎么拿?别违法!
训练数据从哪来?总不能等黑客来攻击吧。
我们用了“红蓝对抗”思路:
- 蓝军:正常用户流量(脱敏后)
- 红军:自己写的爬虫脚本(模拟各种攻击手法)
我用Puppeteer + Playwright写了几十种爬虫变体:有的带真实浏览器指纹,有的随机Sleep,有的伪造Touch事件……甚至还模拟了“人类滑动轨迹”来绕过滑块验证。同事看我整天跑爬虫,还以为我要去干黑产。
⚠️ 注意:爬自家网站没问题,但千万别爬别人家的!尤其是涉及登录、付费内容的。我司法务专门发邮件警告过三次。
数据标注靠规则+人工复核。比如:同一IP在一分钟内请求50次非公开API,且无JS执行痕迹 → 标为恶意。初期误报率高,后来加入“行为序列”特征(比如是否先访问首页再点详情页),准确率才稳住。
安全视角下的ML部署陷阱
作为安全工程师,我最怕的不是模型不准,而是被对抗攻击。
比如:攻击者知道我们在用ML反爬,就故意制造“正常行为”来污染模型。或者探测特征边界,找到绕过阈值的方法。
所以我们做了几件事:
- 特征混淆:不直接用原始IP,而是用IP的哈希+地理位置聚类后的ID;
- 动态阈值:根据时段、业务活动自动调整判定阈值(比如大促期间放宽);
- 模型版本灰度:新模型先对1%流量生效,监控误杀率;
- 拒绝服务防护:如果单个IP触发太多模型推理,直接限流——防CPU被打满。
另外,模型本身也是攻击面!我们把模型文件权限设为只读,禁止动态加载外部模型,防止RCE。毕竟,谁能想到model.pkl也能被用来反序列化攻击呢?
效果如何?数字说话
上线两周后,数据如下:
| 指标 | 上线前 | 上线后 | 变化 |
|---|---|---|---|
| 恶意请求拦截率 | 62% | 89% | ↑27% |
| 误杀率(正常用户被拦) | 0.8% | 0.3% | ↓0.5% |
| API平均延迟 | 45ms | 48ms | +3ms |
| 运维告警次数(因爬虫导致) | 12次/天 | 2次/天 | ↓83% |
最爽的是,上周某个竞品公司派爬虫来扒我们课程价格,直接被模型识别+IP封禁。产品总监在群里@我:“兄弟,牛逼!” ——那一刻,我觉得加班听Lo-fi也值了。
写给同行的几句真心话
- 别迷信算法:在工程落地面前,99%的SOTA模型都是花瓶。能跑起来、跑得稳、跑得快,才是王道。
- JS也能玩ML:别被语言绑架。Node.js + 轻量模型,在边缘场景非常香。
- 安全和ML是天然CP:异常检测、欺诈识别、日志分析……安全工程师搞ML有天然优势——我们天天和“异常”打交道。
- 爬虫是工具,不是敌人:善用它生成对抗样本,才能打造更鲁棒的防御系统。
最后吐槽一句:产品经理现在又想让我上“AI驱动的零信任架构”……我默默打开了招聘软件。
不过说真的,这次经历让我意识到——未来的安全工程师,不懂点ML,可能连漏洞都挖不动了。毕竟,攻击者早就开始用GAN生成钓鱼页面、用强化学习绕过WAF了。
我们,也该跟上了。
P.S. 代码已脱敏并开源在内部GitLab,欢迎来提PR(或者一起吐槽产品经理)。🎧

评论 0