文章总结: 本文揭示了GitHub的Git签名验证存在哈希链延展性漏洞。攻击者无需私钥或改代码,仅通过篡改签名原始字节即可生成不同Hash但仍获Verified标签的Commit,从而绕过基于Hash的黑名单与溯源机制。其根源是平台未对签名进行规范化。建议开发者继续固定完整CommitHash,而平台方和CI/CD工具必须在验证前严格规范化签名编码以消除盲区。 综合评分: 92 文章分类: 漏洞分析,供应链安全,安全建设
破防了!GitHub的“Verified”绿标签名也能被伪造?
原创
Kit Chung Kit Chung
安全圈动向
2026年7月13日 08:07 广东
在小说阅读器读本章
去阅读
大家好,作为开发者,我们在刷 GitHub 的时候,看到 Commit 旁边那个绿色的 “Verified”(已验证)徽章,是不是总会有一种莫名的安全感?在大部分 IT 人的认知里,一个带有验证签名的 Git Commit Hash 就像是代码的“身份证”——绝对唯一,不可篡改。
但如果我告诉你,这个“身份证”其实可以被“克隆”呢?
最近,卡内基梅隆大学(CMU)的博士生、Cure53 的密码学审计员 Jacob Ginesin 发布了一项最新的研究成果,直接打破了我们对 Git 签名的固有认知。今天我就带大家扒一扒这项研究,看看那些不改一行代码,却能让 Commit Hash 随意变换的“黑魔法”到底是怎么回事。
🤯 颠覆认知的“双胞胎” Commit
大家先想一个场景:如果某段代码有问题,你通过它的 Commit Hash 将其拉黑了,这就万事大吉了吗?
Ginesin 的研究指出:在没有私钥的情况下,任何人都可以拿着一个已经签名的 Commit,伪造出一个拥有相同文件、相同作者、相同时间,且签名依然有效的新 Commit。 最离谱的是,GitHub 依然会给这个新 Commit 盖上 “Verified” 的认证戳。
唯一的区别是:它的 Commit Hash 变了。
这就意味着,攻击者完全可以换个新 Hash,把你拉黑的“毒代码”重新推上来,轻松绕过基于 Hash 的黑名单防御机制。不仅如此,依赖 Hash 的代码去重系统、溯源日志(Provenance Logs)以及可复现构建记录,统统都会受到这个软肋的威胁。
核心痛点:
很多系统都把“已验证的 Commit Hash”当成内容的永久唯一标识,但这其实是个美丽的误会。
🛠️ 扒一扒底层的“骚操作”:哈希链延展性
为什么会出现这种情况?原作者将其称为 “哈希链延展性”(Hash Chain Malleability)。
在 Git 的底层逻辑里,Commit 的 Hash 值是根据其包含的所有内容计算出来的,这其中就包含了 Header 里的签名原始字节。如果我们要修改 Hash 却不碰代码,只要能改变签名的字节,同时保证签名依然合法就行了。
Ginesin 团队甚至开源了一个工具,完整复现了针对不同加密算法的三种篡改路径。这里我给大家拆解一下其中的技术细节:
-
ECDSA 密钥(椭圆曲线魔法):
这是经典的椭圆曲线代数特性。在签名中,值
s和n - s在数学上都是合法的。攻击者只需要翻转这个值,就能改变签名的字节形态。这种形态不仅能通过本地的git verify-commit校验,还能成功骗过 GitHub 拿到绿标。 -
RSA 和 EdDSA 密钥:
攻击者可以在签名的“未哈希”(unhashed)区域塞入一些无用的额外字段。这部分数据原本就是设计来被签名机制忽略的,所以签名校验依然通过。但由于 Commit 的整体字节发生了改变,Hash 值也就随之变化了。
-
S/MIME (X.509) 密钥(结构篡改):
这种方式更加底层,通过将签名 DER 结构中的一个长度字段重写为更长、非标准的形式来实现。虽然本地严格的
gpgsm校验会拒绝它,但 GitHub 却“宽容”地给它打上了 “Verified” 标签。
根本原因在哪里?
其实归根结底,是因为 GitHub 在校验签名之前,没有对签名进行规范化(Normalize)处理。它没有对 S/MIME 强制执行严格编码,没有剥离 OpenPGP 的多余字段,甚至直接接受了非规范的 ECDSA 值。更要命的是,GitHub 只针对 Hash 记录一次 “Verified” 状态并且不再复查,导致即便签名密钥被吊销,这个 Commit 依然金身不破。
🕰️ 历史重演?这题比特币做过!
看到这里,搞过区块链和密码学的兄弟们可能已经会心一笑了。没错,这个核心套路非常古老。
当年比特币就遭遇过一模一样的 ECDSA 签名延展性攻击。任何人都可以翻转交易签名中的 s 值,在没有私钥的情况下改变交易 ID(TXID)。比特币当时的解法是:强制只接受“Low-S”形式,并在后来通过隔离见证(SegWit)将签名从交易 ID 中剥离了出去。
Git 和代码托管平台现在面临的问题,本质上是同一道题。解法也很明确:在信任 Hash 之前,先对编码进行规范化。 这并非什么前沿的密码学难题,而是一个经典的工程教训。
🛡️ 辟谣与应对:你需要慌吗?
看到这儿,有些小伙伴可能会担心自己的代码库被投毒。这里我必须给大家吃一颗定心丸:
-
这不是哈希碰撞!
SHA-1 和 SHA-256 并没有被攻破。并没有人能强制让两份不同的代码共用一个 Hash;恰恰相反,是一份相同的代码可以被写成多种合法的 Hash 形式。
-
代码内容绝对安全!
每一个副本中的文件都是百分之百一致的。如果你通过特定的 Hash 去拉取代码,要么拉到你期望的精确内容,要么拉取失败。它无法用来夹带私货。
那么,谁需要采取行动?
对于我们普通的开发者来说,什么都不用做。你在 GitHub Actions 或者模块依赖中固定(Pin)完整 Commit Hash 的好习惯,依然是防御供应链攻击的最佳实践。
真正需要干活的是各大代码托管平台(Forges)以及 CI/CD 系统的构建者:
-
平台方:
需要在验证之前对签名进行严格的规范化。
-
工具链:
如果你的工具依赖 Commit Hash 来做拦截、去重或记录溯源,请先进行验证和规范化,不要盲目信任一个可能被重新编码的签名对象的原始 Hash。
💡 小贴士: 像 Nix 这样除了验证 Commit,还会对拉取下来的文件内容计算独立 Hash 的系统,就天然具备更强的免疫力。
早在今年 1 月和 3 月,Ginesin 就已经向 GNU、Git 和 GitHub 报告了这个问题。但截至论文发表,各大平台似乎都还没有完全修复它。尤其是 S/MIME 这个本地校验都会报错、GitHub 却依然放行的坑,无疑是平台方最该优先填补的盲区。
技术的演进总是伴随着不断的“踩坑”与“填坑”。这次的发现虽然不至于引发行业地震,但也确实给我们敲响了警钟:在安全领域,理所当然的常识,往往最经不起推敲。
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:安全圈动向 Kit Chung Kit Chung《破防了!GitHub的“Verified”绿标签名也能被伪造?》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。











评论