
Git 3.0 的发布可能让开发者付出巨大的时间成本与焦虑,却换来微乎其微的实际收益,而这一潜在危机尚未被广泛察觉。
Git 本质上是一个内容寻址数据库。存储和传输数据时,Git 对内容进行哈希计算,以哈希值为键存储内容。相同内容在全球范围内始终生成相同的哈希值,确保了数据不被重复存储。提交记录编码前一个提交的哈希值,形成完整性传播机制:若不改变后续所有内容的哈希值,就无法篡改任何历史内容。这赋予了 Git “密码学完整性”。
自 2005 年 Linus Torvalds 创建 Git 以来,SHA-1 一直是其默认哈希算法。过去 20 年间,SHA-1 表现良好,数十亿计的文件、树和提交从未发生过意外碰撞。然而,随着 2017 年 SHAttered 和 2020 年 SHA-1 is a Shambles 等碰撞攻击方法的公开,SHA-1 在数学上被视为半“损坏”状态。尽管目前尚无实际利用案例,但理论上的攻击已成为可能。
因此,经过大量研发,即将发布的 Git 3.0 计划将默认哈希算法从 SHA-1 更换为更强大的 SHA-256。
“损坏”的定义与现实威胁
在密码学领域,“损坏”并不意味着算法无法使用,而是指找到碰撞不再是数学上不可能的。借助现代 GPU 集群,攻击者只需花费数万美元即可人为构造两个内容不同但哈希值一致的文件。这带来了两种主要攻击类型:
- 碰撞攻击:攻击者预先生成两个哈希相同的文件(一良性一恶意),在获得信任后用恶意文件替换良性文件。由于哈希匹配,Git 无法察觉差异。
- 第二原像攻击:攻击者针对特定目标文件,创建一个能匹配其哈希值的恶意文件。但包括 MD5 在内的广泛使用的哈希函数均能有效免疫此类攻击,SHA-1 更是远强于 MD5。
现实可行的攻击主要依赖碰撞攻击,这意味着攻击者必须预先计算并计划注入。然而,即使假设 SHA-1 极易被破解,攻击者仍面临如何分发恶意文件及诱导执行的难题。
在源代码管理(SCM)世界中,哈希并非真正的信任机制。Linus Torvalds 曾指出,信任基于“你从哪里拉取代码”。现实中,恶意代码植入多源于社会工程学攻击(如获取 npm 包写入权限),而非昂贵的哈希碰撞。相比暴力破解哈希,贿赂或接管开源项目维护者更为简单、廉价且高效。
因此,行业被迫进行的 SHA-256 迁移所防御的攻击场景并不切实际。若将 SHA-1 仅视为生成唯一密钥的手段,并接受哈希本身不建立信任,则无需替换。否则,我们将陷入因理论漏洞而不断迁移生态系统的循环。
迁移代价:生态分裂与工具链崩溃
Git 3.0 的变更将带来高昂且复杂的迁移成本。Google 工程师 Emily Shaffer 曾指出,应对这一问题前景并不乐观。
首先,所有使用 git init 创建的新仓库将默认使用 SHA-256。用户需明确知晓本地与远程仓库的哈希格式,否则将遭遇推送失败等错误。托管平台需同时支持两种格式,增加了服务器负载及信任复杂性。
对于现有项目,转换哈希算法将破坏所有现有签名,导致分支分裂。此外,包含 SHA-1 哈希值的旧链接将失效,全球依赖固定哈希长度的内部工具可能崩溃。由于大多数 Git 库不支持双格式,大量脚本和工具将在新仓库中故障。
鉴于问题广泛且缺乏共识,Google 甚至考虑通过内部系统级覆盖,强制新项目继续使用 SHA-1,以逆转 Git 3.0 的默认设置。
替代方案:独立内容验证
作者认为,这是一种为解决理论问题而不必要的方案。对于真正关心安全性的项目,可采用更简单的方法:保留 SHA-1 用于内容寻址,同时引入独立的哈希算法(如 SHA-256 或 BLAKE3)用于签名验证。
具体而言,在签名提交或标签时,独立计算树内容的哈希值,并将其作为新头信息注入对象中。这样,签名同时涵盖了基于 SHA-1 的历史记录和独立计算的内容哈希。Colin Walters 开发的 git-evtag 自 2015 年起已实现类似功能。
该方法允许在不迁移整个生态系统的情况下,为特定项目增加信任向量。测试显示,即便对包含 210 万个文件的 Chromium 项目进行校验,生成校验和仅需 5 秒。这不仅避免了生态分裂,还通过双重哈希机制提升了安全性。未来若新算法被攻破,只需添加新的哈希验证方式,无需再次迁移。
结论明确:不要使用哈希来建立信任。对于 99% 与可信源合作的用户,哈希碰撞攻击无关紧要;对于剩余 1% 的高安全需求场景,独立内容签名是更优解。