密码存储演进历史

小小码农 2021年10月01日 992次浏览

起初,密码是以明文形式存储的,恶意用户可以通过SQL注入等攻击手段获取大量用户名和密码进行"data dumps"(数据转储)。随着越来越多的用户认证成为现实,公共安全专家意识到我们需要做更多的工作来保护用户的密码。

为了防止以上情况的发生,从明文存储时代转换到了单向散列(hash)存储,如MD5SHA-256等,当用户尝试进行身份验证时,哈希密码将与他们键入的密码的哈希进行比较。这意味着系统只需要存储密码的单向散列即可。如果出现漏洞,也只是暴漏密码的单向散列,无法获取明文信息。然而,有一些恶意用户为了破解这个东东,他们创建彩虹表(Rainbow Tables)进行查找,所谓的彩虹表就是预先计算的明文密码及其对应的哈希值,他们不是每次都猜测每个密码,而是计算一次密码并将其存储在查找表中,如果找到对应的匹配值,则对用户进行身份验证。

鉴于彩虹表的破解,我们有了一种新的东东,叫做加盐密码。不只是使用密码作为散列函数的输入,而是为每个用户的密码生成随机字节(称为salt)。salt和用户密码将通过hash函数运行,生成唯一的hash。当用户尝试进行身份验证时,哈希密码将与存储的盐(salt)的哈希和他们键入的密码进行比较。唯一的salt意味着彩虹表不再有效,因为每个salt和密码组合的哈希都不同。

在现代,我们意识到加密哈希(如MD5SHA-256)不再安全。原因是,使用现代硬件,我们每秒可以执行数十亿次哈希计算。这意味着我们可以轻松地分别破解每个密码。

现在鼓励开发人员利用自适应单向函数来存储密码。使用自适应单向功能验证密码需要大量资源(即CPU、内存等)。自适应单向功能允许配置工作系数(work factor),随着硬件性能的提高,工作系数会增加。建议将工作系数调整为大约1秒,以验证系统上的密码。这种权衡使得攻击者很难破解密码,但代价不会太高,不会给自己的系统带来过多负担。自适应单向函数示例包括bcryptPBKDF2scryptargon2