作者:时绍森

蚂蚁集团高级安全工程师,YASA团队技术一号位。主要从事静态程序分析及其相关技术的研究工作,专注于利用静态分析技术解决多语言代码的安全漏洞发现、风险识别等关键问题。

背景:某战略业务急需 PHP 静态分析能力,业界相关产品的遗漏/误报双高且不支持自定义规则,按过去经验YASA自研新语言"季度起步"。本文记录我们是如何应用AI能力把它压到周级、完成对业务的支撑。

一、为什么是 PHP,为什么是一周

我们的具体场景是:某战略业务急需 PHP 静态分析能力,业界标杆产品在动态语言上的遗漏/误报双高且不支持自定义规则;按过去经验自研一门新语言"季度起步"。

我们用一周走完了"PHP 从 0 到引擎能力支持 → 业务代码库框架适配 → 规则定制 → 自动化运营"整条链路,结果验收:

  • 靶场(开源 xAST 评价体系)准召率 95%+
  • 团标《金融业应用安全测试产品检测能力评估准则·SAST 部分》达到 3 级成熟度
  • 首轮全量扫描在真实业务代码库里跑出 3900+ finding,Agent 自主 triage 后人工最终确认了 490+ 条可利用漏洞链路

为什么 PHP 不能让"AI 直接看 PHP 代码"?

因为研发流程要的是硬卡点——CI 几分钟内必须出结果、必须可阻断、必须有可解释的 source→sink 链路。这是 SAST 几十年沉淀下来的工程位置,一个智能体跑十分钟给一段自然语言判断,进不去发布闸门。命令注入、SQL 注入、SSRF、XXE、文件包含、反序列化这些有明确语义模式的高危漏洞,引擎跑过程间污点分析就能给出确定性结论,比让 AI 一条条"理解再判断"更准、更快、更便宜

而 PHP 是出了名的"语法复杂 + 持续演进 + 弱类型 + 包/模块机制特殊"的动态语言。要把这门语言接到一套已有的多语言静态分析引擎上,需要解决的不是"AI 写 parser"这么简单的问题,而是整条链路:UAST 前端 → 引擎语义适配 → 业务框架建模 → 规则配套 → 漏洞运营。下面按这条链路展开,但在进入具体五阶段之前,先讲讲 PHP 这件事是怎么组织起来的。


二、PHP 接入不是"AI 黑盒 Coding",而是"AI 沿专家路径"

先讲一个反例。

如果你把一个高复杂度的统一多语言 SAST 引擎代码丢给 AI,说"帮我加 PHP",结果几乎一定是:AI 在引擎里东改西改、随手添加 PHP 专用 hack、污染共享的底层引擎,跑出来的 PHP 数字看似漂亮,回到 Java/Go/Python 一测全是回归问题。这条路我们实验过,走不通

PHP 这次能跑通的是另一条路:把"跨语言建设"这件事本身抽象成一份 AI 可执行的标准路径,让 AI 沿着专家走过的路落地,而不是让 AI 拿着代码自由发挥。

我们把这件事写成了一份 skill(你可以理解为给 AI 看的 SOP),核心就是 PHP 这次实际走的这张图:

① UAST parser 完备
       ↓
② Benchmark + 成熟度 case 设计(xAST 评价体系 / 团标对齐)
       ↓
③ 所有 Checker 原子化检出能力补齐(通用层适配,不污染底层)
       ↓
④ 目标代码库框架适配(业务框架 entrypoint / source 建模)
       ↓
⑤ 自动化运营(triage agent + 规则反哺闭环)

每个阶段有:目标、验收口径、典型坑、跨仓库提交边界、Worker 拆分建议。skill 里还沉淀了一份"高发陷阱表"——比如 npm link 改完不重编译会读到旧产物、runtime.execute 覆盖默认 passthrough 导致 taint 断链、文件级 entrypoint fallback 会让动态语言产生重复 finding……这些都是过去多语言建设里踩过的坑,写成显式规则就能让 PHP 这次第一轮就避开。

PHP 这件事的关键不在 AI 多聪明,而在我们把"专家经验"显式化、结构化、可被 AI 执行——AI 只是沿着这条路把 PHP 走完一遍。


三、PHP 这周谁在干活:虚拟 AI Team

PHP 这一周,YASA工程师数字分身组织了一个虚拟 AI Team 来落地:

Partner(战略 / 路线 / 全局看板)
   ↓ DIRECTIVE.md
Task Leader(拆任务、调度 Worker、review、合并)
   ↓ TaskCreate + Agent spawn
Worker × N(侦查 / 实现 / 测试 / triage)

Leader 收到一个 PHP 子任务(比如"补 trait 方法解析"或"靶场二级 case 扩充"),第一步不是动手,而是先拆——按文件、按子能力、按 case 分组并行交给 ≥2 个 Worker。Worker 在隔离的 worktree 里干活,每 30 分钟回报一次结构化进度,被阻塞立刻 ping。Leader 自己只做几件事:拆分、调度、审查 Worker 的代码、合并到 PHP 任务分支、回写状态。

这套架构解决了 PHP 这次面对的一个非常实际的问题——单一 AI Context 装不下"PHP UAST + 引擎适配 + 五大类 checker + 业务框架 + 运营智能体"的全貌。把上下文压力分摊到多个 Worker,每个 Worker 只关心自己的小切片,Leader 维护全局看板。

PHP 这次一周里,我作为人类只做了几件事:

  • 在关键路口做技术判断("这个能力是该进通用层还是 PHP 语言层")
  • 在数字异常时质问("你这个 PHP 召回提升的口径是什么")
  • 在 AI 走错方向时拉回来("不要在引擎底层加 PHP 专用分支")

其他全部是 AI Team 自己跑。


四、阶段 ① — UAST parser:把 PHP 的"骚操作"翻译成统一中间表示

PHP 从早期的面向对象,到后续的类型提示、nullsafe、constructor promotion、match 表达式、readonly 属性、非捕获 catch……每一版都在加新糖。

YASA 用一套统一的 UAST(Unified AST)覆盖所有语言。这一阶段的工作是写 parser-php:把 PHP 源码经 tree-sitter 解析后,按 UAST schema 输出干净、无歧义的中间表示。

PHP 在 UAST 翻译这一步踩到的"语法糖"非常多,我们把它们整理成了一份修复模式表:

类别

表现

修复模式

隐式 self

$this 被识别成普通 Identifier

显式输出 ThisExpression

构造函数标记

构造函数没打 isConstructor

按命名约定(__construct)匹配

Constructor Promotion

参数直接声明为字段

UAST 层补齐 this.x = x 赋值

tree-sitter field 缺失

childForFieldName('arguments') 返回 null

改用 namedChildren.find 按节点类型找

Trait/继承

关键字节点未并入 supers

supers 数组拼接

这套修复模式不是 PHP 特有的——很多动态语言都会撞上类似问题。我们把它沉淀进 skill,下一门动态语言接入时第一轮就能避开 80% 的陷阱。


五、阶段 ② — 靶场建设:把"准召率"和"成熟度"做成可重复的 gate

光把 parser 跑通不算数,必须有可重复的评测基线。这一阶段我们在开源 xAST 评价体系下建了完整 PHP 靶场:

  • accuracy + completeness 两大类组织
  • 1~4 级成熟度 分层
  • 每个 case 配 _T(应检出)/ _F(不应误报)和 evaluation info

最终成绩:

  • 团标《金融业应用安全测试产品检测能力评估准则·SAST 部分》PHP benchmark 达 3 级成熟度
  • 开源 xAST 准召率 95%+

这两个数字不是手工统计的——是 calculate-maturity 工具基于 expect 基线算出来的,每次回归都可复算。后续任何引擎改动都能直接看到 PHP 准召率的 delta,不会"改完不知道有没有退化"。

工程纪律:靶场 case 必须落在公开仓库,禁止出现内部业务名/真实接口路径,这条边界在 PHP 这一轮严格守住了。


六、阶段 ③ — Checker 全栈:在 YASA 多语言通用引擎上补齐 PHP 语言层

这是 PHP 接入工作量最重、最考验工程方法的一步。

YASA 的污点分析引擎是语言无关的,核心能力(过程间数据流、上下文敏感、对象与字段敏感、流敏感与路径敏感、别名分析)一旦在 UAST 上生效,就同时服务所有语言。PHP 这一阶段的工作,是在 YASA 多语言通用引擎之上补齐 PHP 的语言特性和包/模块管理机制,让 PHP 自动继承引擎的污点追踪、callgraph、callchain 等通用能力——而不是为 PHP 重写一套分析框架

具体补齐了五块:

  • 污点源登记:把 PHP 的超全局变量这类天然用户可控输入纳入引擎的 source scope,污点链路从入口就接得上
  • 包/模块管理:跨文件 include/require 翻译成同一作用域的延续,跨文件定义的函数、类、sanitizer 自然进入同一条数据流——这是模式匹配类工具天然做不到的边界
  • 面向对象语义:对象/字段敏感、继承与 trait 的方法解析、魔术方法作为隐式调用点
  • PHP 标准库行为建模:对没有源码的内置函数预先给出 passthrough / sanitize / source 先验,避免污点一接触标准库就断链
  • 引用与别名:PHP 的引用传参、别名赋值、数组下标别名打通到引擎已有的别名分析

这五块支撑起来之后,污点追踪、callgraph、callchain 这些重型能力在 PHP 上就直接可用了。

铁律:所有 PHP 特判(弱类型 calleeType 通配、按引用语义、魔术方法分派)只能落到语言层<lang>-analyzer / <lang>-default-taint-checker),禁止污染底层共享引擎。每次试图在底层加 if (lang === 'php') 都会在 review 时被打回——这条纪律守住了"加 PHP 不让其他语言回归"的底线。


七、阶段 ④ — 业务框架适配:让引擎"懂业务代码长什么样"

光有 PHP 语言层不够。真实业务代码里,"用户可控输入"和"接口入口"都是经过框架封装才出现的,不是赤裸的超全局变量。

PHP 这次在业务代码库里需要做两件事:

  • Source 适配:业务里大量的 getParam / getHeader / getUnSafeData 这类包装方法才是真正的用户可控输入起点。我们用一个 Source 识别 Agent自动扫描业务代码、识别这类 getter 链路、产出 source 配置,再人工 review 一遍。
  • Entrypoint 适配:业务里同时存在标准 MVC Controller、内部 SOA 服务接口、自研的跨应用数据集散组件。每一类都有自己的基类/目录/注解特征。引擎层暴露了"Entrypoint Collector"扩展点,PHP 业务里每种框架对应一个 collector 文件,互不耦合。

这一步的关键在于理解一份从没见过的业务代码库的框架风格,并把理解转化成可执行的 collector + source 配置——这是 PHP 这次最贴近业务的一段工作。


八、阶段 ⑤ — 漏洞运营:从"扫一次"到"持续闭环"

企业级 SAST 的真正难点不是"扫描",是"扫完之后怎么办"。PHP 首轮跑出 3900+ 条 finding,人工逐条看就是几个月。

我们用一个漏洞运营 Agent把这一步闭环:

  1. 逐条 triage(禁止抽样、禁止族级推断),状态枚举:exploitable / not-exploitable / unreachable / deadcode / duplicate-of:<id>
  2. 每条卡片记录:source / sink / caller 状态 / 可利用性 / 置信度
  3. 历史标签复用:前轮 confirmed 的真阳性直接采纳
  4. 真实漏洞产出结构化报告,含 CWE / 严重度 / source→sink 跳链 / 一句话危害描述
  5. 反哺规则:SARIF dedup、新 sink 发掘、sanitizer 收敛——每条规则改动 → 类型检查 0 + 全语言 benchmark 回归 + 原项目重扫 delta 可解释

PHP 这次首轮跑了 3900+ 条 finding,Agent 自主 triage 后人工最终确认了 几百条 可利用漏洞,真阳性率约 12.8%(业界 SAST 工具典型水平)。涵盖命令注入、代码执行、SQL 注入、SSRF、XXE、文件包含、文件读取、任意文件上传、HTTP 头/日志注入九类高危场景。其中包含几条 CRITICAL 级未鉴权 RCE 后门入口——这是任何模式匹配类工具都难以发现的语义级链路。


九、PHP 这次留下了什么

PHP 这一周不是只交付了"PHP 能扫"这一件事,这次建设的 PHP 语义能力,会直接成为后续 PHP 代码审计智能体的底座

  • PHP UAST:把所有语法糖归一到统一中间表示——后续 PHP 智能体读 UAST 比读源码更稳定、更短、更省 token
  • 过程间调用图、跨文件 include/require、虚表方法解析、魔术方法分派:智能体直接复用,不用自己重建
  • 对象/字段敏感的污点流、超全局污染源、框架 entrypoint:智能体拿来当"业务上下文"的输入
  • Source 自采集 Agent、漏洞运营 Agent:本身就是智能体形态,可以直接长出"水平越权检测 Agent"等业务逻辑类能力

也就是说:SAST 守研发上线卡点的硬规则,智能体在 SAST 语义能力之上做业务逻辑类漏洞——水平越权、垂直越权、业务流程绕过这些没有固定语法模式、需要"理解业务语义"的漏洞,正是智能体能发挥的地方。两条战线分工清晰,共用一份语义底座。

PHP 这次把底座建好了,下一步在这个底座上长 PHP 代码审计智能体,边际成本比"从零理解 PHP 代码"低一个数量级。


十、写在最后

PHP 一周端到端支持上线,不是"AI 突然能很好的写YASA代码了",是几件事在 PHP 这次同时成立:

引擎的通用层在 PHP 之前就已经语言无关、跨语言建设经验已经显式化成可执行的 SOP、Source/Triage 这些 Agent 在 PHP 之前就已经做出来可复用。PHP 这次只是把这些既有资产用到一门新语言上,再把 PHP 特有的语言特性和包/模块机制按既定路径补齐。

点击了解【开放式统一多语言程序分析产品YASA

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐