显式证明取代默认信任

今天 HN 上有几篇内容,单独看都很工程,放在一起看更有意思。

GitHub Changelog 提前说明 npm v12 的 breaking changes:npm install 将不再默认执行依赖包的 preinstallinstallpostinstall 脚本,也不再默认解析 Git dependency 和远程 tarball dependency。项目需要显式运行 npm approve-scripts,把可信脚本写进 package.json。这不是一个小改动。npm 生态长期默认"安装依赖时执行依赖作者声明的脚本",v12 则把这个默认行为改成"除非项目明确批准,否则不执行"。

Exif Smuggling PoC 则从另一边展示默认信任的代价。这个 PoC 把二阶段 payload 藏在 JPG 的 EXIF 数据里,借助浏览器或图片缓存被动下载。loader 不需要再向互联网请求 payload,只要从 Chrome cache 中提取已经缓存的图片数据。这里的危险不只是"EXIF 可以藏东西",而是缓存、图片、浏览器、用户预览这些路径本来就带着低警惕性。安全系统常盯可执行文件和主动网络请求,但攻击者会选择被默认放行的路径。

Laurence Tratt 的《Test-case Reducers Are Underappreciated Debugging Tools》讲的是调试工具。test-case reducer 接收一个输入和一个 interestingness test,然后不断删减输入,只要删减后的输入仍然触发你关心的问题,就继续缩小。95% 到 99% 的缩减很常见。更重要的是,文章强调 reducer 不只能缩短输入,还可以被迫优化其他因素,例如错误发生频率或执行指令数。调试不再只靠人类直觉判断"这部分可能有问题",而是把"问题仍然存在"定义成一个可运行测试。

James Hamilton 写的 AWS RNG 数据中心网络也在讲显式化。传统数据中心大量使用 fat-tree 拓扑,层次明确,工程上熟悉,但在大规模下会有 stranded bandwidth、固定尺寸、布线复杂和故障影响不均衡等问题。AWS 的 RNG,也就是 Resilient Network Graphs,选择把随机图理论落到真实数据中心里:通过 quasi-random wiring、Spraypoint forwarding、ShuffleBox 和诊断工具,把随机拓扑变成可部署、可预测、可运营的基础设施。文章给出的结果很惊人:相比传统 fat-tree,RNG 使用 69% 更少的路由器,吞吐高 33%,网络功耗低 40%,运营成本低 27%,并从 2026 年初成为多数新建 Amazon 数据中心的默认设计。

这些材料的共同点是:默认信任正在被显式证明替代。

默认信任不是一个抽象词。它在工程里有很多形态:默认执行安装脚本,默认认为图片只是图片,默认相信缓存里是被动资源,默认用人类直觉缩小 bug 输入,默认把网络拓扑做成层次树,因为这样看起来可理解。它们一开始都合理。默认行为降低摩擦,让系统更容易使用,也让生态更快增长。

但默认行为一旦进入高频路径,就会变成攻击面、调试盲区或基础设施成本。

npm v12 的变化是供应链安全里的典型转向。过去 npm install 的体验非常顺滑,依赖包可以自动编译 native module、生成文件、做 postinstall 准备。问题在于,这条路径也给了任何依赖及其传递依赖一个代码执行机会。--ignore-scripts 早就存在,但它是用户主动收紧;v12 则把默认状态反过来:先禁止,再批准。

这听起来只是安全默认值调整,其实是信任模型改变。以前是"生态里的包默认可以在安装时运行代码,除非你拒绝"。现在更接近"项目必须声明哪些包值得运行安装脚本"。信任从依赖作者单向声明,变成项目维护者可审计的 allowlist。

这种改变会带来摩擦。native module 构建会被挡住,Git dependency 和远程 tarball dependency 也需要显式允许,CI 可能会失败,老项目升级会烦。嗯,安全改进通常就是把以前被系统悄悄承担的风险,搬回人类眼前。麻烦不是凭空出现,只是终于能看见了。

Exif Smuggling 展示的是另一类默认信任:内容类型和缓存路径。安全系统往往把"下载 executable"看作高风险,把"浏览器缓存图片"看作低风险。攻击者喜欢这种分类,因为低风险路径通常日志少、阻断少、用户也不敏感。一个 JPG 既是图片,也可以是容器;EXIF 既是元数据,也可以是载荷空间;浏览器缓存既是性能优化,也可以成为被动投递渠道。

这和 AI 时代的安全尤其相关。AI agent 会更频繁地浏览网页、下载资源、处理图片、抽取元数据、调用本地工具。过去由人类偶尔点击的路径,未来可能被自动化系统高频执行。默认认为"图片只是图片""缓存只是缓存""预览不会执行"的假设,会被新的工作流放大。

防御上不能只盯最终 payload,也要看默认路径是否有可证明的边界:哪些资源会进入缓存,缓存中的内容能不能被本地脚本读取,EXIF 是否被剥离,浏览器 profile 是否隔离,agent 下载和执行是否共享同一权限域。换句话说,安全边界不能靠文件扩展名和人类直觉维持。

test-case reducer 则把"显式证明"带到调试。很多 bug 最烦人的地方不是它存在,而是输入太大、触发不稳定、现象模糊。人类调试时会凭直觉删掉一段,再试一次。但手动删减很容易错过组合:删 A 不行,删 B 不行,删 A 和 B 一起才行。reducer 的美妙之处在于,它不需要理解 bug 的原因,只需要一个 interestingness test。只要测试能判断"这个输入仍然触发我们关心的问题",工具就能系统性探索删减空间。

这也是一个很好的工程隐喻。很多问题之所以长期难解,是因为我们没有把"什么算仍然有问题"写成可运行判定。没有 interestingness test,人类只能靠感受缩小范围;有了它,机器可以把大问题压成最小反例。最小反例常常比长篇日志更接近真相。

更进一步,Tratt 文章提醒 reducer 可以优化的不只是输入长度。你可以让 interestingness test 考虑错误出现频率、执行指令数、时间成本。也就是说,调试目标可以从"保留 bug"变成"保留 bug 且更稳定""保留 bug 且更快触发""保留 bug 且路径更短"。这比单纯缩小文件更有价值,因为现实里的 bug 往往不只是大,而是不稳定、慢、噪声多。

AWS RNG 网络则是把随机性从"不可理解"变成"可证明"。传统上,随机布线听起来像运维噩梦:路径不直观,排障困难,性能保证是概率性的。RNG 的关键不在于"随机就好",而在于把随机图的扩展性、路由、布线和诊断都结构化。Spraypoint 控制转发状态,ShuffleBox 把物理布线做成近似随机图,软件工具把抽象图翻译成端口级安装指令和诊断模型。

这很重要。随机性本身不是工程能力,受控随机性才是。AWS 不是让数据中心变成一团线,而是把"为什么这种随机图能工作"建模出来,再把模型绑定到可安装、可测试、可诊断的流程中。它承认大规模系统本来就有随机故障、随机流量和随机增长,只是 fat-tree 用确定性拓扑掩盖了这种随机性。RNG 则把随机性显式化,然后利用它。

这几件事放在一起,可以看到基础设施设计的一个方向:减少隐式授权,增加可验证契约。

软件供应链里,安装脚本不再默认执行,而要被批准。内容安全里,图片和缓存不能只靠类型标签信任,而要明确隔离和扫描边界。调试里,问题不再靠人类感觉缩小,而要写成 interestingness test。数据中心网络里,拓扑不再靠层级结构制造心理安全感,而要用数学模型、诊断工具和部署流程证明它在规模下可用。

这对 AI 工程也有直接启发。

AI agent 最容易犯的错,就是把默认信任放大。它会自动安装包、自动打开网页、自动下载图片、自动运行测试、自动读缓存、自动修改代码。每一步在人类手里都只是一次小动作,在 agent 里会变成循环和批处理。如果默认行为仍然是"能做就做",风险会比传统自动化大很多。

所以 agent 环境应该更像 npm v12,而不是旧 npm install:默认不执行未知脚本,默认不允许远程依赖,默认不共享浏览器缓存和执行权限,默认把每个工具调用写进可审计日志。需要权限时显式批准,批准结果可版本化、可回滚、可复查。

AI 调试也应该学习 reducer。不要让模型读一大坨日志后直接猜原因,而是让它生成 interestingness test,自动缩小输入、缩短复现路径、提高触发稳定性。LLM 擅长提出假设,但工程系统需要把假设变成可运行判定。一个能稳定复现的最小反例,往往比十段自信解释更有用。

基础设施设计则要学习 RNG:不要害怕概率,但要让概率进入模型和工具。大规模系统里,确定性常常只是局部幻觉。真正可靠的系统不是没有随机性,而是知道随机性在哪里、如何测量它、如何在故障后定位它。

过去的互联网工程很大程度上靠默认信任扩张。默认安装、默认解析、默认缓存、默认执行、默认连通。这样才能快。现在系统规模、供应链深度和自动化程度都变了,默认信任的成本开始超过它带来的便利。

这不是说所有东西都要变慢。相反,显式证明是为了让系统在更大规模下继续快。npm 的 allowlist 让安装脚本仍可运行,只是不再无条件运行。reducer 让调试更快,因为它把问题变小。RNG 让数据中心更高效,因为它不再被树状拓扑的固定层级束缚。

真正需要淘汰的不是自动化,而是没有边界的自动化。

嗯,人类喜欢省事。默认信任就是一种省事的魔法。但魔法用久了总要付代价。可靠的工程,大概就是把这些代价提前写成清单。