为何不直接用 SHA-256?
像 这样常规的密码学哈希是完整性的正确工具,却是存储密码的错误工具,原因恰恰是那个让它在别处出色的性质:它很快。一个窃取了 SHA-256 密码哈希数据库的攻击者,在普通硬件上每秒可尝试数十亿次猜测,因为每次猜测只是一次快速哈希。常见密码几乎瞬间沦陷。速度,这个通用哈希的美德,在此却是负担。
密码存储需要一个有意放慢且能抵御专用硬件的哈希。三个构件让它奏效:加盐、一个可调的工作因子和内存难度。
加盐:击败预计算
盐(salt)是与每个密码哈希一同存储、并被混入哈希过程的一个唯一随机值。没有盐,相同的密码会产生相同的哈希,于是攻击者可以一次性预计算出一张巨大的常见密码哈希表(“彩虹表”,rainbow table),并瞬间查到每一个匹配。每个密码一个唯一的盐使这种预计算变得毫无价值:攻击者必须逐一攻击每个哈希,而同一个密码对每个用户哈希得各不相同。现代密码哈希函数会为你生成并存储盐。
工作因子:让每次猜测都昂贵
工作因子(或成本参数)控制每次哈希需要多少计算。把它设定到这样的程度:单次哈希足够慢,以至于在一次合法登录中无从察觉(几百毫秒),但在规模上却是惩罚性的。因为它是一个参数,你可以随着硬件加速而逐年提高它,使猜测的成本大致保持恒定。这正是通用哈希根本没有的那个旋钮。
三个标准选择
- bcrypt 是长期存在、广为理解的选项,建立在 Blowfish 密码之上,带有一个可配置的成本因子。在可用之处是一个安全的默认。
- scrypt 增加了内存难度:它有意消耗一个可调的内存量,这会钝化使用 GPU 和定制芯片的攻击者,因为这些硬件扩展计算远比扩展内存便宜。
- Argon2 在 2015 年赢得了 Password Hashing Competition,是当前对新系统的推荐。它是内存困难的,对内存、时间和并行度有各自独立的旋钮;Argon2id 变体是通常的选择。
这其中任何一个都是合理的选择;首要规则是使用其中之一,绝不用一个赤裸的快速哈希,也绝不发明你自己的方案。
结论
把 SHA-256(在 哈希工具 中)用于校验和与完整性,那里速度是一个优点。对于密码,请伸手去取 bcrypt、scrypt 或 Argon2,那里缓慢与内存成本正是全部要义。这两项工作看似相似,却要求相反的工具。