哈希函数详解
哈希函数可以把任何输入转换成简短、长度固定的“指纹”。本指南说明 MD5、SHA-1 和 SHA-256 适合做什么、有哪些不足,以及如何将文件与公布的校验和进行比对。
什么是哈希
加密哈希函数读取任意大小的数据,生成固定长度的摘要:MD5 为 128 位,SHA-1 为 160 位,SHA-256 为 256 位,通常以十六进制文本显示。相同的输入每次都会得到相同的摘要,而输入哪怕只改变一位,得到的摘要也会截然不同。哈希是单向的:除了猜测输入并比较结果之外,无法从摘要还原输入。
本指南提供的是一般信息。在作出安全决策时,请遵循您所在组织或所使用服务的要求。
校验和与完整性
日常最常见的用途是检查文件是否完好无损地送达。下载页面可能会在文件旁公布一个 SHA-256 值。下载后,您计算自己副本的哈希值,并与公布的值进行比较。如果两者一致,该文件很可能与发布者计算哈希的文件完全相同;如果不一致,说明下载已损坏,或者文件是另一个版本。
只有当公布的值本身可信时,校验和才有意义。如果攻击者能同时修改同一页面上的文件和校验和,哈希一致也说明不了什么。数字签名用于解决这个问题。
为什么 MD5 和 SHA-1 不能用于安全目的
安全的哈希应当使人在实际中无法找到两个摘要相同的不同输入(即碰撞)。针对 MD5 和 SHA-1 的实用碰撞攻击均已公开,攻击者可以构造出两个哈希值相同的不同文件。因此,它们已不再被认为适合用于数字签名、证书或其他安全用途。
MD5 和 SHA-1 仍然可以检测意外损坏,一些较旧的系统也仍在公布这些值。对于新的工作,通常选择 SHA-256 或 SHA-2 家族的其他成员(SHA-384、SHA-512)。
| 算法 | 摘要长度 | 安全状况 |
|---|---|---|
| MD5 | 128 位(32 个十六进制字符) | 已可构造碰撞;仅用于旧式校验和 |
| SHA-1 | 160 位(40 个十六进制字符) | 已可构造碰撞;旧系统沿用 |
| SHA-256 | 256 位(64 个十六进制字符) | 广泛使用,推荐 |
| SHA-384 / SHA-512 | 384 / 512 位 | 广泛使用,推荐 |
哈希不是加密,密码需要更多保护
加密在拥有正确密钥时是可逆的;哈希则并非为逆向而设计。不过,哈希无法隐藏简短或可预测的输入:任何人都可以对常见单词或电话号码计算哈希,再查找匹配项。
因此,仅使用 MD5 或 SHA-256 这样的快速哈希并不适合存储密码。它们的设计目标是快速,这使攻击者能够迅速测试大量的猜测。密码存储使用专门为此设计的、加盐的慢速算法,例如 Argon2、scrypt 或 bcrypt。如果您要构建登录系统,请使用持续维护的库并遵循您所用平台的现行指导,而不是使用通用哈希。
用于消息认证的 HMAC
普通哈希可以显示数据是否发生了变化,但任何人都可以重新计算它。HMAC(基于哈希的消息认证码)将数据与密钥结合,例如 HMAC-SHA256。只有知道密钥的人才能生成正确的值,因此接收方可以检查消息是否来自密钥持有者,且未被篡改。Webhook 和 API 请求签名通常使用 HMAC。请妥善保管密钥;任何拥有密钥的人都能生成有效的认证码。
为什么相同的文本会得到不同的哈希值
哈希是根据字节计算的,而不是根据您看到的文本。以下差异会改变结果:
- 换行符:Windows 使用 CR LF,而 Linux 和 macOS 使用 LF。
- 字符编码:“é”在 UTF-8 和较旧的编码中对应不同的字节。
- 末尾的换行或空格,或文件开头的字节顺序标记(BOM)。
- 输入中的大小写。
哈希值不一致时,请先检查这些方面。对原始文件计算哈希通常比对从中复制的文本计算哈希更可靠。十六进制输出本身不区分大小写:A1B2 和 a1b2 是同一个值。
常见问题
可以解密 MD5 或 SHA-256 哈希吗?
不可以。哈希不是加密的数据。在线“解密”服务是在预先计算好的常见输入的哈希中查找,这也是简单值的哈希几乎起不到保护作用的原因。
验证下载文件应该使用哪种算法?
使用发布者提供的算法。如果提供了多种,SHA-256 或 SHA-512 比 MD5 或 SHA-1 更好。
哈希生成器会上传我的文件吗?
LeedyBox 哈希生成器在您的浏览器中计算哈希,因此您选择的文本或文件在您的设备上处理。