您是不是在下载页、Git 提交记录或者安全文章里见过一长串 40 位的十六进制字符,却不太确定它到底是什么、安不安全?简单讲:那是 SHA-1 算出来的“指纹”,而 SHA-1 早就不能再当作安全的指纹来用了。
结论先说:2017 年,谷歌和荷兰 CWI 研究所做出了两份内容不同、SHA-1 值却完全一样的 PDF,这次攻击叫 SHAttered。它证明 SHA-1 已经抵挡不住“故意制造碰撞”,新系统请改用 SHA-256 或 SHA-3;存密码则要用专门的慢哈希算法。
下面小编按“哈希是什么、碰撞为什么危险、攻击怎么做到的、现在该怎么办”的顺序,带您捋一遍。
什么是密码学哈希函数?
哈希函数可以把任意大小的输入(一个密码、一份文档、一个安装包)压缩成固定长度的结果,这个结果叫“哈希值”或“消息摘要”。SHA-1 的结果是 160 位,通常写成 40 个十六进制字符。
一个合格的密码学哈希函数,一般要满足四点:
- 确定性:同样的输入,永远得到同样的输出。
- 计算快:处理大文件也不费劲。
- 单向性:拿到哈希值,推不回原文。
- 抗碰撞:想故意找到两份不同内容、却得到相同哈希值,在现实中应该做不到。

SHA-1 栽的跟头,就在第四条:研究人员证明,故意制造碰撞已经能以可接受的成本做到。
什么是哈希碰撞?
碰撞,就是两份不同的输入算出了同一个哈希值。从数学上讲碰撞一定存在,因为输入是无限的,输出长度却固定。安全设计的要求不是“碰撞不存在”,而是“想故意找到一对,要花的算力大到不现实”。
对一个理想的 160 位哈希,利用“生日悖论”,找一对碰撞大约需要 280 次运算,这已经远超暴力计算的能力。SHA-1 的问题在于,密码分析者找到了数学上的捷径,把所需工作量压到了远低于这个理想值。
SHAttered 攻击到底发生了什么?
2017 年 2 月 23 日,谷歌和荷兰 CWI 研究所宣布,他们找到了完整 SHA-1 的首个实用碰撞,并公开了两份看上去不同、SHA-1 值却相同的 PDF。详情可以看谷歌的官方公告,以及 CWI 的研究发布。
这次计算规模很大,但对资金充足的团队是可行的。谷歌公布的数字大致是:
- 约 9.22 × 1018 次 SHA-1 运算;
- 第一阶段相当于 6500 年的 CPU 计算量;
- 第二阶段相当于 110 年的 GPU 计算量。
注意,这些“年”是把大量机器的算力加总后的折算值,并不是一台电脑真的跑了几千年。谷歌估计,这种攻击比通用暴力碰撞快 10 万倍以上。
两份不同的 PDF,为什么能有相同的哈希?

SHA-1 是按块处理数据的:每处理一块,就用一连串位运算更新一次内部状态。研究人员并不是碰运气,而是用“差分密码分析”,研究两份消息之间精心设计的差异,在内部计算中会怎样传播。
他们构造出特殊的“碰撞块”,让两份消息先分叉,再把 SHA-1 的内部状态重新拉回到一起。内部状态一致后,两份文件接上相同的后续内容,最终摘要自然一样。这次成功的关键,是利用了 SHA-1 结构上的弱点,而不是单靠蛮力去撞整个 160 位空间。
SHA-1 碰撞危险在哪?
很多系统把哈希值当作数据的“身份证”。如果它默认“一个哈希值只对应一份内容”,那么被人故意制造的碰撞就会打破这个假设。受影响的场景包括:
- 依赖抗碰撞性的数字签名;
- 文件完整性校验;
- 证书体系;
- 内容寻址存储;
- 版本控制系统里的对象标识;
- 把哈希当唯一标识的去重系统。
要说清楚一点:碰撞攻击不等于“能反推出密码”。那是另一种安全属性。SHA-1 被证明失守的是抗碰撞性,不过它已经过时到,新设计根本不该再用。
2017 年之前,SHA-1 就已经被怀疑了
2005 年前后,就有重要的密码分析成果表明 SHA-1 的抗碰撞强度明显低于理论上的 80 位。美国 NIST 随后推动大家转向 SHA-2。NIST 自己的说明里提到,2011 年弃用 SHA-1,2013 年底起禁止用于数字签名。所以 2017 年的碰撞,更像是给一个早已开始的迁移再添一把火。
想看原文,可以读 NIST 对这次研究的官方回应。
SHA-1 现在还能用吗?
“抗碰撞场景下已经被攻破”和“任何历史用途都立刻作废”,是两回事。NIST 在过渡期里仍允许少数遗留用法,比如验证部分旧签名,或不依赖抗碰撞性的特定构造。但官方态度很明确:能迁走就尽快迁走。
NIST 计划在 2030 年 12 月 31 日前完成这一过渡,此后 SHA-1 不再是 FIPS 140 验证密码模块中的批准算法。最新政策见 NIST 哈希函数政策页面。
用什么替代 SHA-1?
新系统需要通用密码学哈希时,NIST 推荐 SHA-2 或 SHA-3 家族。SHA-256 属于 SHA-2,是目前最常见的默认选择。截至 2026 年,公开资料里还没有能像 SHAttered 攻击 SHA-1 那样攻击 SHA-256 的实用碰撞方法。
| 算法 | 在新安全设计中的状态 | 建议 |
|---|---|---|
| MD5 | 已被攻破 | 不要用于需要抗碰撞的安全场景 |
| SHA-1 | 抗碰撞性已被攻破 | 尽快迁移旧系统 |
| SHA-256(SHA-2) | 当前批准的算法家族 | 多数场景的好默认值 |
| SHA-3 | 当前批准的算法家族 | 内部设计不同,是有力的备选 |
为什么迁移 SHA-1 这么慢?

换个哈希算法,听起来只是改一行代码。可一旦哈希写进了长期使用的数据格式或信任体系,事情就复杂了。大型机构里,SHA-1 可能藏在这些地方:
- 很难升级的固件;
- 仍需验证的旧数字签名;
- 证书数据库;
- 文件归档和去重索引;
- 工业系统;
- 老协议;
- 应用接口与序列化数据格式;
- 被脚本、数据库和文档引用的版本控制标识。
迁移时要回答一堆兼容性问题:旧标识还有效吗?旧软件能读新格式吗?两套哈希要不要并存一段时间?历史签名怎么继续验证?这就是为什么即使替代算法早已成熟,密码迁移也常常要拖上好几年。
Git 和 SHA-1 是什么关系?
Git 历史上用 SHA-1 给对象命名:每个提交、目录树、文件内容和带注释的标签,都有一个由内容算出的 SHA-1 标识。所以 SHAttered 对软件开发圈格外有冲击——直觉上,两个不同的 Git 对象似乎也可能被造成同一个身份。
Git 后来加入了多重防护,也一直在推进向 SHA-256 的过渡。官方文档描述了一种用 SHA-256 命名对象的仓库格式,并可维护 SHA-256 与 SHA-1 名称之间的对照。详见 Git 的哈希函数过渡文档。不过这不代表所有仓库都已经转换,兼容现有工具、托管服务和老仓库,比换个函数调用难得多。
日常提交代码,会中 SHA-1 攻击吗?
普通开发不必看到每个 40 位提交号就紧张。实用碰撞攻击需要精心构造的数据,现代 Git 和托管平台也部署了针对 SHAttered 的碰撞检测。更大的启示是架构层面的:不要再把纯 SHA-1 的抗碰撞性当作可信的安全边界。
SHA-1 能用来存密码吗?
不能。就算撇开碰撞不谈,纯 SHA-1 也不适合存密码,因为它设计得太快,攻击者每秒能试海量猜测。存密码要用专门的慢哈希或密钥派生函数,并加盐、设置合适的工作量,比如 Argon2id、scrypt、bcrypt 或 PBKDF2。把 SHA-1 换成纯 SHA-256,并不会自动让一个不安全的密码库变安全。场景和算法一样重要。
哈希不等于加密
哈希是单向的;加密则是让持有密钥的人能还原原文。用安全的加密算法加密文件,保留密钥就能解密;而对文件算 SHA-256,没有任何“反哈希”操作能从摘要还原文件。哈希、加密、数字签名和密码哈希,解决的是不同的问题。
怎么用 SHA-256 校验下载文件?
如果官方提供了 SHA-256 值,您可以对自己下载的文件算一遍再对比。
Windows PowerShell:
Get-FileHash "C:\path\to\file.iso" -Algorithm SHA256 Linux:
sha256sum filename.iso macOS:
shasum -a 256 filename.iso 两个值必须逐字符一致。不一致,说明您的文件和发布者对应的文件不是逐字节相同。还要提醒一句:校验值本身必须来自可信渠道。如果攻击者能同时替换下载文件和页面上的校验值,对比就证明不了真伪。
常见问题(FAQ)
SHA-1 是什么时候被攻破的?
弱点很早就有人指出,但完整 SHA-1 的首个实用碰撞,是 2017 年 2 月 23 日由谷歌和 CWI 公开的。
真的有两个不同文件的 SHA-1 值一样吗?
有。SHAttered 项目做出了两份看起来不同、SHA-1 摘要完全相同的 PDF。
SHA-1 碰撞会泄露密码吗?
不会。碰撞攻击和破解密码是两回事。不过纯 SHA-1 依然不适合存密码,因为太快,也缺少现代密码哈希的保护。
SHA-256 被攻破了吗?
截至 2026 年,公开资料里没有与 SHAttered 同级别的 SHA-256 实用碰撞攻击,NIST 仍批准 SHA-2 家族。
新软件还要不要用 SHA-1?
不要。需要抗碰撞的通用哈希时,选 SHA-256 或其他获批的 SHA-2/SHA-3 即可。
为什么 Git 里还是 40 位的哈希?
Git 历史悠久、兼容要求高,迁移很复杂。Git 已支持向 SHA-256 仓库过渡,但现有的 SHA-1 仓库和标识依然非常普遍。
小结
SHA-1 不是因为电脑碰巧算出了两个相同的值而失败,而是研究人员找到了结构性攻击,让“故意制造碰撞”变得可行。SHAttered 是决定性的演示,但警告信号早在十多年前就出现了。这给密码学上了一课:算法不会因为曾经被认为安全,就永远可信。
小编的建议很简单:新系统别再把 SHA-1 当抗碰撞的安全组件;普通哈希用 SHA-2 或 SHA-3;存密码用专门的密码哈希;设计系统时,也留好“将来能换算法”的余地。
