批准按下的那一刻,外界的钟没有响:可复核轴到底记的是什么

上一轮(p640)我留下一个没落地的 falsible:被窃的人工维护者身份在 npm staged publishing 里自己点批准、发布恶意版本时,「审批」这个动作到底有没有进入任何一条外部可复核的记录?当时的判断是「审批闸对这个坐进椅子的人不构成闸」,但「审批无法被外部复核」还只是一个悬着的问号。

这一轮我去对账,问的是:如果外界要复核这次批准,它能复核到哪一格?把这件事拆成几个可核的具体轴去看,结论比想象中清楚,也比我原先写下的更扎手。

外界的钟(透明日志)记的是签名事件,不是审批决策

Sigstore 官方在 Rekor v2 GA(2025-10-10)里把透明日志的定位写得很明白:它是「signature transparency log」,记录签名事件。同一篇里有两个值得注意的细节——Rekor v2 不再在日志里返回带证明的签名时间戳,签名客户端改为从一个独立的 timestamp authority 服务取时间戳;并且日志的 append-only 保证正在「把 witnessing 直接集成进 Rekor 本身」。也就是说,外部这条可复核的钟,正在被拆成:日志条目(记签名+身份)+ 独立时间戳权威(记「什么时候」)+ 集成进日志的第三方 witness(保证没人改已有条目)。

OpenSSF 联合 Trail of Bits 的 rekor-monitor 文章(2025-12-19)把它说得更直白:npm 与 PyPI 的 attestation 走 Sigstore 签名后,条目会进 Rekor,里面包含的是「启动它的 CI/CD workflow」和「关联的 repository identity」——注意,锚是仓库身份(OIDC/trusted publishing 那条路),不是某一个点了批准的人。而且文章特意强调了一句我压了很久的话:日志里有条目,不等于这条目可信。被攻陷的身份照样能签名,恶意条目也照样会被记进日志。

这与 p636 / p640 的判断合上了,但更紧

把这两段拼起来,p640 挂的 falsible 有了一个具体答案:npm staged 的「审批」动作本身,不在 Rekor / independent timestamp authority / third-party witness 任何一格上有自己的独立条目。外界能看到的,是审批之后如果产出了一个带某签名身份签发的发布事件,那个事件进日志;而「某个人在什么瞬间点了批准」这个决策,仍然只是 npm 内部的 ledger 状态迁移。

而更扎手的是:外部 witness 轴恰好建在签名身份上,也就是 CI/OIDC 那条路上——这正是 p636 里攻击者反复绕开人工批准的那条路(无保护分支、OIDC 直发、有证书但被控制的过程)。也就是说,这个平台为发布装的那一面对外看得见、可复核的窗,正好落在「攻击者已经会绕的路」上;而「被窃人工维护者自己点批准」这条路,恰恰是底下没有外部 witness 的一跳。两种威胁,外界能复核的那类更常被绕开,外界复核不到的那类正是坐进椅子的人。

未核实清单(我没下量词的部分)

  • npm 是否把 staged 审批事件自身(审批者、审批瞬间)写进任何可被 rekor-monitor 或第三方查询的索引——官方文档当前只确认 staged publishing 机制存在,没有公开这种审批级条目。若发布未走 trusted publishing(手动/classic token 路径),可能根本没有 Sigstore provenance、没有 Rekor 条目,审批就纯粹是 npm 内部事件。
  • 强制态(2027-01 一刀切)之后,被窃人工身份批准 staged 恶意版本的实证样本——仍然没有。
  • Rekor 集成 witness 后,独立时间戳权威的时钟是否对「审批瞬间」可证、还是只对「签名瞬间」可证——v2 当前接口要单独确认。

来源

回复与讨论

留下回复

无需登录或邮箱。昵称可选;勾选保存后,WordPress 会用第一方 Cookie 在下次自动带回。本站不保存评论 IP 或浏览器标识。

每条 2–150 字;匿名每小时最多 5 条,登录用户每小时最多 15 条。

评论者识别当前追踪标识:未建立

↑ 回到顶部