Git 3.0 默认切 SHA-256:迁移账单先到

Git 3.0 默认切 SHA-256:迁移账单先到

Git版本控制密码学安全工程基建

数据源:HN + web research

Git 3.0 的目标是 2026 年底把新建仓库的默认对象格式切到 SHA-256,同期还要强制 Rust 编译链、默认改用 reftable、删掉一批老命令。离发布还有缓冲期,但周边工具链的兼容检查现在就该做。

默认值一改,周边生态全要重新验证

官方强调旧格式仓库升级后依旧能稳定运行。这套说辞试图将破坏性圈定在增量项目上。但在真实工程环境里,只影响新仓库就等同于粗暴切断存量生态的平滑演进。开发者只要在本地新建实验库,旧版 IDE 插件就会罢工。年久失修的发版脚本,也会当场撞上双轨解析的报错红墙。

致命隐患在于周边工具链对 40 字符哈希的根深蒂固依赖。现在新仓库默认标识符直接膨胀到 64 字符。字符串宽度的突变,摧毁了过去十几年写下的硬编码提取规则。各类持续集成系统的日志读取模块,会在接触新格式节点信息的第一时间抛出截断异常。

数据库示意图 图:Git 以内容哈希做键值数据库的示意图。来源:GitButler / Butler’s Log

Git 自 2018 年起就支持按需启用 SHA-256,敏感项目可以主动切换。八年窗口期内主动承担迁移负担的项目屈指可数,改变默认值因此成了唯一能把迁移真正推下去的手段。

碰撞攻击跟第二原像根本不是一回事

NIST 早在 2011 年就把 SHA-1 列入弃用名单,标准机构的态度已经摆了十几年。核心团队推动默认值切换,公开理由就是不想让新仓库继续建立在一个已被弃用的算法上。

反对者 Chacon 指出这混淆了不同级别的安全威胁。安全界在 2017 年 SHAttered 计划和 2020 年 Shambles 论文中,公开了针对旧算法的冲突方法。但让两份刻意准备的文件算出相同散列值,不代表攻击者能在未知原内容时精准伪造恶意代码。

工程现实中,针对底层仓库的第二原像破解依然造价高昂且缺乏可操作性。就算把校验降级成已被停用的 MD5,调集约 30 亿块高端 GPU 跑满算力,破解预期时间仍在 160 亿年量级。现有通用硬件规模根本填补不了理论漏洞与现实攻击间的算力缺口。

要复现论文里的碰撞攻击同样缺乏操作性。黑客必须先取得目标写权限,把精心编造的畸形源码混入提交中。随后还要诱骗上游维护者拉取特定分支。自己搭建恶意环境再去诱导合并,这种渗透路径在真实黑产活动中毫无回报可言。

信任只看拉取来源而不看加密哈希

技术争论触及了控制体系架构的安全边界。Linus Torvalds 早在 2005 年就公开定调,真实的防线体现在分发环节,而不是依靠特定公式。决定主机环境安全下限的核心,是从哪个可信服务器拉取更新。这远比底层磁盘文件经过哪种校验要关键。

真实供应链渗透往往采用社会工程学手段。攻击者更习惯直接掏钱收买无人维护的模块作者。他们也愿意潜伏伪装成贡献者,骗取项目合入权限。2024 年 xz 恶意后门事件就是典型渗透。拿到代码变更权限后直接植入木马,远比费力制造碰撞要廉价得多。

把算法强度当成挡住恶意注入的主力,覆盖不到构建流水线上的鉴权死角。签名有效的标签下替换掉最终分发包,不需要任何碰撞。拦住脏数据要靠发布通道的严密程度,散列换多长都补不上这个口子。

迁移账单结不平:两种格式没法混用

变更默认值最难处理的是存量项目平移,它不会在后台默默生效。

哈希格式界面 图:托管平台建仓时必须选择哈希格式的界面示意。来源:GitButler / Butler’s Log

团队在私有平台上建仓必须手动对准两端规范。一旦本地环境与服务端的算法配置产生分歧,推送过程就会受阻。代码会被底层直接拦截,并抛出不支持当前对象格式的致命错误。

转换大型存量仓库会把积累多年的历史数据洗掉重来。把存量旧库转化为新标准,意味着重写全量基础对象。这种洗牌会导致历史节点上的所有数字签名当场失效。知识库和工单系统里留存着大量旧提交链接。底层转换完成后,它们会一夜之间变成死链。

主干与子模块的绑定机制放大了生态割裂感。当前运转规则要求嵌套项目必须处于同一种数据格式。跨格式引用的支撑模块必须在构建服务器上长期维护两套独立的依赖拷贝。底层依赖如果处理不好双轨同步,整个团队自动化流水线就会停摆。

许多不依赖原生底层调用的解析封装包,对新算法支持迟缓。业界传闻 Google 内部甚至打算制定硬性规章。他们可能会要求全公司的所有增量项目退回使用旧版格式。大厂宁愿硬性叫停底层升级,就是为避免把高级工程师耗费在排查兼容报错上。

替代方案把计算成本压在签名环节

开发组对新标准的推行并非心血来潮。邮件列表上关于过渡周期的互操作映射设计早铺垫了多年。从建设者视角看,用短暂阵痛换取未来数十年的防篡改保障,是符合逻辑的演进路线。基础框架设计者往往倾向在架构层面封堵所有弱点。

社区反对派则聚焦于将防御成本降到可控区间。独立维护者主张跳过全局存储层的替换。他们选择在提交签名对象里附带一个单独计算的内容验证头。

写入签名对象 图:独立内容哈希写入签名对象字段的示意图。来源:GitButler / Butler’s Log

这种设计把防篡改计算压力转移到了签名阶段。它迫使试图造假的人必须同时攻破两套互不相关的验证体系。

采用单独验证头的优势在于隔离开发开销。根据实测,给包含 210 万个文件、容量 35 GB 的 Chromium 仓库重算校验码仅耗费 5 秒。处理 Linux 的 1.5 GB 代码树只需 257 毫秒,常规小型项目更是 17 毫秒出结果。把计算负担压在打发行标签那一瞬,日常海量提交就不必再缴纳额外算力税。

把代码库推入新标准,换来的是往后几十年的安全余量;不改默认值,省下的是整个生态的迁移账单。两边的前提其实很清楚:认为哈希本身就是信任基础,迁移就该尽早做;认为信任来自拉取来源,迁移的紧迫性就没那么高。邮件列表上讨论多年的格式互操作映射,是这次变更唯一现实的缓冲垫。

参考链接:

  • Git 3.0 and the SHA-256 Migration
  • The hidden cost of Git’s SHA-256 migration