密码存储
如果您的应用程序需要对用户进行身份验证,那么很可能也需要处理密码。
处理用户密码是一件大事,而正确处理用户密码更是一件大事。
很难想象还有比应用程序遭到攻击、用户密码在互联网上泄露给所有人看更糟糕的情况了。我们个人对此不寒而栗。那么,如何根据最佳实践安全地存储密码呢?让我们来看看几种方法。
加密与散列
从表面上看,人们可能会认为加密听起来是安全存储密码的一个不错的解决方案,但是,完全依赖加密可能会带来一些问题。
加密本质上是一种双向功能,这当然意味着密码可以被加密,也可以被解密。完全符合逻辑,对吗?否则,如何验证用户密码是否与数据库中存储的密码一致?
因此,密码解密能力也是一个相当大的隐患。如果有人入侵服务器并获取了密码密文,那么他们也很有可能获取解密密码所需的关键材料。
而散列由于其单向性,更适合密码。哈希算法一旦完成,就无法直接将密文变回原始的纯文本。这一特性使得哈希算法成为保护密码的唯一选择。
并非所有哈希值都一样
一旦决定采用散列方式存储密码,也不是简单地应用散列函数就可以了事的。
哈希值有各种形状和大小,鉴于过去十年来计算技术的进步,其中大部分并不完全适合用于存储密码。
如前所述,由于散列是单向函数,因此无法逆转。虽然这在技术上是正确的,但散列也是确定性的,这意味着它们也容易受到暴力破解策略的影响,只要有足够的时间和资源,攻击者就有可能将散列逆转为原始纯文本。
因此,我们将散列函数分为两类:
- 加密哈希值
- 密码散列
密码哈希值的一个主要特点是它们有一个 "工作系数"(可以是一个整数,也可以是多个参数),用来定义计算哈希值所需的工作量。
随着 CPU 和 GPU 的速度越来越快,在消费级硬件上对哈希值进行大规模暴力破解攻击变得越来越容易,这意味着随着时间的推移,哈希值的安全性会越来越低。
工作系数 "用于确保哈希值的存储方式符合行业趋势。硬件速度越快,算法的工作系数就越大,以确保哈希值的解密需要更多的时间和精力。举例来说,在当代硬件上需要 100 毫秒。
这意味着,在实践中,工作系数可能需要每 2-3 年提高一次。