AI 删掉输入校验后,先查清信任边界
编程智能体可能因发现上游校验而删除共享函数中的防护,却遗漏路由、消息处理器等其他入口。文章建议将删除校验视为待核查问题,确认所有调用路径后,再恢复检查或将其移至真正的外部输入边界。
AI 深度解读
AI 编程助手把函数里的输入校验删了,理由是「调用方已经检查过」。这类改动看起来像清理重复代码,实际可能拆掉了系统拦截坏数据的最后一道关卡。原文的结论很明确:先把删除当作待核实的问题,证明所有外部输入仍会被拒绝,再决定能不能合并。
这篇值得读的地方,是把「在入口校验一次」拆成了可检查的条件:入口到底在哪里、调用方有没有漏、异常数据能否真的被挡住。对经常让 AI 重构公共函数的程序员,这比一句「注意代码安全」具体得多。
为什么「调用方已经校验」不能直接当证据
作者认为,编码 Agent 在简化函数、消除重复或压平调用链时,容易把注意力放在当前改动及其可见路径上。它沿着一条正常调用链往上看,发现上层做过相同检查,就可能判断内层校验多余。
原文用下面这行代码说明容易被删掉的守卫,它负责在发现不含 @ 的 email 时抛出错误:
if (!email.includes("@")) throw new Error("bad email")
要注意的是 throw 所在的整行:删除它以后,函数就开始依赖调用方提供合格参数。这个示例也只检查是否包含 @,不能据此把它当作完整的邮箱格式校验。
「在边界校验一次」这个原则没有问题,难点是找全边界。信任边界(trust boundary)就是外部数据进入系统、开始被内部代码当作可信数据使用的位置。请求体、队列消息、webhook 和存储记录,都可能跨过这条线。
静态导入关系未必能展示所有入口。框架路由、消息处理器和反序列化后的数据,都可能走到同一个函数。Agent 看见某个调用方检查过参数,不等于已经证明其他路径也检查过。
看见重复校验,只能说明可以考虑合并,不能证明可以直接删除。
删掉一行之前,要证明哪两件事
原文给出的安全前提有两个:所有调用方都位于信任边界以内,而且每个调用方都在调用前完成校验。
这两个条件还得经得住后续改动。今天只供内部使用的 helper,下个季度可能被新路由复用;当前校验完整的调用方,也可能在重构时丢掉检查。问题未必马上出现,可能隔一段时间才表现为数据库里的畸形记录、价格计算中的 NaN,或者某条路径因缺少字段而崩溃。
审查时,应该寻找「约束是否消失」,而不只是确认代码有没有搬家。重点包括删除的 throw、针对空值或越界值提前返回的 if、正则检查,以及 schema 解析。函数变短了,却开始默认参数格式正确,也属于需要追查的信号。
作者建议把本地 Git diff 与解析器提供的定义、调用方、导入关系放在一起看,再逐个检查调用方实际执行的校验。函数名叫 validateSomething,不能代替阅读函数内容。
如果解析器没有找到入向引用,也不能判断函数无人调用。它可能只是看不见那个入口。
修复则分两种情况:如果函数完全私有,且只有一个公共入口覆盖所有调用路径,可以把校验集中到那个入口;如果存在多个入口,保留靠近共享函数的守卫,能让各条路径都必须经过检查。恢复被删的校验,是尚未查清边界时的安全默认选择。
怎么证明校验还在起作用
代码里存在检查,与实际请求会触发检查,是两件事。
原文要求从公共入口发送一条格式错误的请求,确认系统拒绝它。静态阅读能证明某行代码还在,运行验证才能进一步证明这条路径确实执行了它。即使一次异常请求被拒绝,也仍要结合调用关系,确认其他入口没有绕过检查。
类型系统同样不能替代这一步。TypeScript 可以约束编译时的代码,却不能自动保证运行时收到的 JSON、webhook payload 或环境变量符合声明的类型。
原文提到的 Powerduck,会把被标记的校验删除与 diff、调用方和导入证据放在一起,并能导出交接包,让编码 Agent 带着上下文恢复检查。这是作者介绍的工具能力,原文没有给出具体项目实测、检出率或对照数据。
作者也明确承认,审查可能误报、漏报,看不到动态加载或外部消费者,而且不会运行应用。它返回的优先级、证据和建议,只能作为验证线索。缺少可运行脚本时,应标为「未验证」,不能算作通过。
我的判断
我认同把「删除校验」单独列为审查信号。它很容易混在重构里,功能测试又常常只覆盖合法输入,代码看起来更整洁,约束却已经变弱。
但不能把文章理解成「每层都保留相同检查」。边界明确、入口统一时,集中校验确实能减少重复;多个入口共享业务函数时,靠近共享函数保留约束也有理由。判断依据应该是哪些路径受保护,而不是校验代码出现了几次。
还要区分文本相同与责任相同。两段检查即使长得一样,也可能分别守着不同边界,删掉其中一段之前仍需检查覆盖范围。
Powerduck 是否比人工阅读 diff、搜索调用关系、补充异常输入测试更有效,原文没有提供对照证据。这部分应当作为工作流建议看待,不能据此替工具效果背书。
能拿来做什么
- 让 AI 重构 Node 接口或公共 helper 时,在任务里明确要求:删除参数校验必须说明替代检查的位置,以及哪些调用路径会经过它。
- 审查 AI 生成的 diff 时,优先查看被删掉的
throw、提前返回和 schema 解析,再追查对应函数的实际入口,避免只检查新增代码。 - 对同时被 HTTP 路由、队列消费者或 webhook 使用的函数,逐条确认校验路径,并从相关入口发送异常数据,检查是否按预期拒绝。
- 把「检查存在」「异常输入已验证」「当前无法运行」分别记录清楚;缺少脚本或运行条件时,保留未验证状态,不把静态审查当成测试通过。