← 返回目录

第 1 卷

第 1 / 4 卷日期:

20|Agent 的规则进化:从异常请求中长出候选规则

张嘉熙 · DeepSeek Harness 前沿工程实践

图 1-1
图 1-1
图 1-2
图 1-2
图 1-3
图 1-3
图 1-4
图 1-4

你好,我是张嘉熙。

上一讲我们把“写规则”这件事从人手里交给了 Agent。但上一讲的起点仍然是人说出来的一句话——阻止所有访问 /admin 的探测,Agent 才有东西可译。系统不会自己去看日志,得出

“最近 /admin 被扫描得厉害,该加一条规则”。需要一条什么样的规则,还是得由人先想清楚。

这一讲补的就是这个缺口:起点换成 nginx 原始访问日志里的异常请求,让系统自己看出该加什么。这里有两个独立环节:谁来生成已经解决了,第 19 讲的 Agent 起草 + 人审批,本讲

照用;生成由谁触发才是这一讲要补的。第 19 讲要等人先说出一句意图才动,本讲让系统自己攒够异常证据就发起一轮提案。

候选规则怎样基于证据生成?

关于环境:本讲示例在配套 cookbook 的 src/firewall/ch20/,需要 DEEPSEEK_API_KEY。候选走 dsh 的 LLM 能力,默认 DeepSeek 模型,从脱敏证据中

生成。

本讲与 dsh 的交集只有两处:证据复用第 19 讲的会话日志注入 user/message,只换来源标记,以及上面这条模型调用链路;而检测与脱敏 observe.ts 只依赖 node:crypto

和 node:fs,是不依赖 dsh 的纯领域逻辑。其余机制由 npm test 钉住,包括检测器与采样 observe.test.ts、候选校验 propose.test.ts、证据写进会话与读回校验

session-observe.test.ts,另有真模型生成候选与失败降级 propose.e2e.test.ts。

关于示例:原料是 nginx 原始访问日志,示例读的是 ch20/access.sample.log,14 行,正常与异常混合。不必真的部署一个 nginx;接真实日志时把路径指到

/var/log/nginx/access.log,但格式要与下面的样本行一致。npm run start:ch20 跑完整链路:增量读日志 → 检测 → 采样 → 脱敏 → 证据进会话 → 阈值达

成 → 生成候选 + 三关校验,末尾还会打印各步的统计,检出几条、采样丢了几条、会话里几条、阈值是否达成,以及模型 token 用量。

异常请求怎样被发现:增量读与检测

我们来看看 nginx 原始访问日志,ch20/access.sample.log,先看其中一行:

复制代码 1203.0.113.5 - - [10/Oct/2026:12:00:02 +0000] "GET /admin HTTP/1.1" 200 0 "Mozilla

它请求的是 /admin,一个敏感路径。这就是本节要发现的异常。

先说读。日志不能每次都从头扫,那样同一批会被反复扫出来,所以要增量读,记着上次读到

inode:文件的唯一编号,文件被换掉就换一个

size:文件大小,用于识别文件是否被截断

字节偏移:内容的真实位置

三者全对上,才确认是同一份日志、可以增量读。

再说检测。读进来的行,靠 detect() 判断是不是异常。这里先分清一件事:第 18 讲的规则引擎是执行规则的,给定规则、判定实时请求该不该拦;而这一步是发现阶段,在规则还

没有自动生成的时候,从历史日志里识别出哪些是异常请求。这一步不能用规则引擎来做,它需要先有规则才能运行,而规则正是本讲要自动产出的。所以改用三个写死的正则,各识别一

类已知攻击特征,顺序敏感,一条请求只归入最先命中的那一类。

path-probe,敏感路径探测:访问 /admin、/wpadmin、/phpmyadmin、/etc/passwd 这类系统敏感路径的请求。

sqli,SQL 注入:路径或参数中带有 '--、union select、;drop table 这类 SQL 注入特征串的请求。

bad-ua,扫描器 UA:User-Agent 标识是 python-requests、curl、scrapy、 zgrab 这类自动化客户端的请求。

三个检测器都只看路径和 UA 两个字段,其余字段如状态码、cookie、ip 等不参与检测。它们怎么用是下一节的事。

拿 path-probe 举例,核心代码节选如下:

复制代码

1constPROBE_SEGMENT=/(?:^|\/)(admin|wp-admin|phpmyadmin|etc\/passwd|\.env|wp-lo
3exportfunctiondetect(line: NginxLine):AnomalyKind|null{
4constpath =decodePath(line.path)//先百分号解码:/%61dmin还原成/admin
全站分卷索引 · 4 卷
  1. 1第 1 卷
  2. 2第 2 卷
  3. 3第 3 卷
  4. 4第 4 卷