首页 > Note > 服务端用户密码的管理

服务端用户密码的管理

2017年12月12日 发表评论 阅读评论

最近做了一些与密码学相关的工作,对于消息的加解密有了一些新的看法。结合之前项目中遇到的服务端密码存储的问题,在这里写一点自己的想法。

目前常见的一些密码存储方式

以下是一些常见的密码存储方式,其中一部分是自己用过的,一部分是见过别人使用的:

  1. 明文 pwd
  2. 经过MD5 哈希后存储 md5(pwd)
  3. 两次MD5后存储 md5(md5(pwd))
  4. 加盐md5存储 md5(pwd + salt)
  5. 密码扩展后存储 kdf(pwd)
  6. 慢哈希后存储 brypt(pwd)
  7. 以上多种算法组合后存储

哈希

很明显,第 1 种是最不安全的。存储在数据库中的密码可以轻易地被管理员看到。一旦服务器被拖库,这些密码就轻易地被别人窃取,并可以根据账号和密码在其它网站上试探(大部分用户在多个网站上使用相同的用户名和密码)。尽管人人都知道这种存储方式是极不安全的,但仍然有很多网站使用它。如前几年震惊中外的 CSDN 拖库事件 。在这一事件中,有600万用户的信息被泄漏。
第 2 种 方式比较古老,管理员和黑客无法看到用户的明文密码。但如我们所知,MD5 是不安全的。如 MD5 碰撞算法。而在此之前,查表法一直做为破解 MD5 密码的重要手段 。 所谓 查表法 ,就是对字典(密码集) 进行 MD5 运算,将哈希值预存储在一个或多个表里。

当需要破解某密码时,根据服务器存储的哈希值在预计算的哈希值表中查找对应的值。而 反向查表法 ,攻击者可以同时对多个重合密码进行攻击。

如果用户使用了弱密码,这种使用反向查表法来破解密码简直不要太轻松。
使用查表法需要存储字典与哈希值,对存储空间有较高的要求。后来进化出了 彩虹表 法,在算法的空间和时间上进行了优化。

加盐

第 3、4 种方式针对上述攻击方法做了改进。其实第 3 种方式并大的改进, 因为算法和参数是固定的。而第 4 种的改进比较好。所谓 加盐(salt) ,即在消息的任意固定位置添加附加消息。它使攻击者的字典变得更加复杂,攻击者计算预存储值的难度大大增加了;每个密码都混入了不同的盐,所以使得反向查表法去批量匹配密码变得难以施行。在加盐存储的实践中,有部分人使用了错误的实现:如盐值过短,或盐值重复。
盐值过短 无法对攻击者造成足够的困扰,一个好的盐值的长度起码要和哈希值的长度一至。而 盐值重复 则和未加盐没有区别:两个相同的密码加相同的盐,得到的哈希值是一样的。特别是对于那些将盐值硬编码到代码里的,简直是在为攻击者提供帮助。类似地,也不要使用用户名、用户id、创建时间等字段做为盐值--盐值应该是随机的,且并用户修改密码时应该给出新的盐值。

加盐存储的一般步骤为:

  1. 使用伪随机函数生成足够长的随机值做 盐salt .
  2. 对混入盐的密码(或密码变体,如密码的哈希值)进行强哈希运算(如 SHA256 而不是 MD5 或 SHA1),得到哈希值 hasl_val .
  3. 将 salt, hash_val 存储到对应的记录 .

相应校验的步骤为:

  1. 在数据库中提取 salt 和 hash_val .
  2. 在密码( 或密码变体)中混入盐,使用相同的哈希函数计算出哈希值 hash_val2
  3. 比对 hasl_val 和 hsal_val2 ,如果一样,则说明密码是正确的.

更加安全的方式,是使用 双salt 。即服务端产生两个 salt, 一个用于服务端,一个用于客户端。客户端在传输密钥前向服务端请求salt, 在客户端加盐处理后再传向服务端。这样的好处除了添加复杂度,还可以定期动态升级盐。
注意:在web客户端使用 js 计算出密码哈希值后再传输的方式并不靠谱 : 中间人攻击可以轻松修改 js 代码。安全的方式是启用 HTTPS 。

密钥扩展与慢哈希

加盐阻止攻击者使用查表或彩虹表快速破解大量密码,但无法阻止字典攻击和暴力攻击。现代计算机运算速度与存储单元价格低廉,配合特别的硬件(如 GPU) ,可以大大提高暴力攻击的速率。为防范这种攻击,可以使用 第 5 或第 6 种方式 : 密钥扩展技术。
密钥扩展 的本质是增加密码的复杂度,降低哈希函数的速度。一些成熟的算法被广泛采用,如 PBKDF, bcrypt 。需要注意的是种方法会降低哈希函数的速度,同时也会占用一些计算资源。这一特性会拖慢服务器的速度,甚至会为Dos 攻击提供帮助。解决的方式是把这一负担分摊到客户端。
密钥扩展函数会带有一个安全因子或迭代因子,它们决定了哈希函数 "慢" 的程度。计算哈希的速度越慢,暴力破解的难度越大。
需要注意的是,客户端的防范并不能替代服务端的防范,在服务端只是接受慢哈希计算出的哈希值,服务端仍需要加盐等安全操作。

其他方式

一般来说,如果被拖库,意味着损失的不仅仅是用户的信息,同一个数据库中的其他数据也会丢失。如果数据的安全性比较高,那么用户信息和应用数据分开存储比较合理。用户信息所以的服务器用于验证服务,用户在登入时首先将用户名和处理后的密码加密后发往验证服务器进行验证,验证完毕后将验证结果加密后发回应用服务器。这样可以更大程度上保证数据安全。
验证服务与应用服务之间应该采用 HMAC 或 GCM 这样带有验证的方法加密。

  1. hi
    2017年12月28日10:28 | #1

    nice 密码学

  2. ConorPai
    2017年12月13日16:34 | #2

    666,大牛端!!!

  3. ConorPai
    2017年12月13日16:33 | #3

    666,大牛端

  1. 本文目前尚无任何 trackbacks 和 pingbacks.