起初,密码是以明文
形式存储的,恶意用户可以通过SQL注入等攻击手段获取大量用户名和密码进行"data dumps"(数据转储)。随着越来越多的用户认证成为现实,公共安全专家意识到我们需要做更多的工作来保护用户的密码。
为了防止以上情况的发生,从明文存储时代转换到了单向散列
(hash)存储,如MD5
、SHA-256
等,当用户尝试进行身份验证时,哈希密码将与他们键入的密码的哈希进行比较。这意味着系统只需要存储密码的单向散列即可。如果出现漏洞,也只是暴漏密码的单向散列,无法获取明文信息。然而,有一些恶意用户为了破解这个东东,他们创建彩虹表
(Rainbow Tables)进行查找,所谓的彩虹表
就是预先计算的明文密码及其对应的哈希值,他们不是每次都猜测每个密码,而是计算一次密码并将其存储在查找表中,如果找到对应的匹配值,则对用户进行身份验证。
鉴于彩虹表
的破解,我们有了一种新的东东,叫做加盐密码
。不只是使用密码作为散列函数的输入,而是为每个用户的密码生成随机字节(称为salt
)。salt
和用户密码将通过hash函数运行,生成唯一的hash。当用户尝试进行身份验证时,哈希密码将与存储的盐(salt)的哈希和他们键入的密码进行比较。唯一的salt
意味着彩虹表
不再有效,因为每个salt
和密码组合的哈希都不同。
在现代,我们意识到加密哈希(如MD5
、SHA-256
)不再安全。原因是,使用现代硬件,我们每秒可以执行数十亿次哈希计算。这意味着我们可以轻松地分别破解每个密码。
现在鼓励开发人员利用自适应单向函数来存储密码。使用自适应单向功能验证密码需要大量资源(即CPU、内存等)。自适应单向功能允许配置工作系数
(work factor),随着硬件性能的提高,工作系数会增加。建议将工作系数
调整为大约1秒,以验证系统上的密码。这种权衡使得攻击者很难破解密码,但代价不会太高,不会给自己的系统带来过多负担。自适应单向函数示例包括bcrypt
、PBKDF2
、scrypt
和argon2
。