术→技巧, 研发

Dropbox账户密码存储实践

钱魏Way · · 205 次浏览

众所周知,存储明文密码是一件很糟糕的事情。如果数据库存储了明文密码,一旦数据泄漏,那么用户账号就危险了。因为这个原因,早在1976年,工业界就提出了一套使用单向哈希机制来安全地存储密码的标准(从Unix Crypt开始)。很不幸的是,尽管这种方式可以阻止你直接读取到密码,但是所有的哈希机制都不能阻止攻击者在离线环境下暴力破解它,攻击者只需要遍历一个可能包含正确密码的列表,对每个可能的密码进行哈希然后跟获取到的密码(使用哈希机制存储的密码)比对即可。在这种环境下,安全哈希函数如SHA在用于密码哈希的时候有一个致命的缺陷,那就是它们运算起来太快了。一个现代的商用CPU一秒钟可以生成数百万个SHA256哈希值。一些特殊的GPU集群的计算速度甚至可以达到每秒数十亿次。

过去的这些年,为了应对攻击,Dropbox对密码哈希方法进行了数次升级。他们的密码存储方案依赖三个不同层级的密码保护,如下图所示:

Dropbox采用 Bcrypt 作为核心哈希算法,每个用户都有一个独立的salt以及一个加密的key(这个key也可以是一个全局的,通常也叫pepper),salt和key是分开存储的。与基础的 Bcrypt 算法在一些重要的方面是不同的:

  • 首先,用户的明文密码通过 SHA512 算法转换成了一个哈希值。这一步主要是针对Bcrypt的两个突出的问题。有些Bcrypt的实现中会将用户输入截取为72个字节大小以降低密码熵,而另外有一些实现并没有截取用户输入导致其容易受到DoS攻击,因为它们允许任意长度的密码输入。通过使用SHA,可以快速的将一些的确很长的密码转换为一个512比特的固定长度,解决了上述两个问题,即避免降低密码熵和预防DoS攻击。
  • 然后,对SHA512哈希后的值使用bcrypt算法再次哈希,使用的工作因子是10,每个用户都有一个单独的salt。不像其他的哈希算法比如SHA等,Bcrypt算法很慢,它很难通过硬件和GPU加速。设置工作因子为10,在服务器上执行一次bcrypt大概需要100毫秒。
  • 最后,使用Bcrypt哈希过后的结果再次使用AES256算法进行加密,使用的密钥是所有用户统一的,称之为pepper。pepper是基于深度考量的一种防御措施,pepper以一种攻击者难以发现的方式存储起来(比如不要放在数据库的表中)。由此,如果只是密码被拖库了,通过AES256加密过的哈希密码对于攻击者来说毫无用处。

为什么不使用scrypt或argon2?

Dropbox曾考虑过使用Scrypt,但是我们对Dropbox有更多的经验。关于这几种算法哪种更好的讨论一直都有,大部分的安全领域的专家都认为scrypt和bcrypt的安全性上相差无几。

Dropbox考虑在下一次升级中使用argon2算法:因为在采用当前的方案的时候,argon2还没有赢得 Password Hashing Competition。此外,从1999年以来,Bcrypt还没有发现有任何重大的攻击存在。

为什么使用一个全局的密钥(pepper)替代哈希函数

如前面提到的,采用一个全局的密钥是我们深度权衡后的一个防御措施,而且,pepper是单独存储的。但是,单独存储pepper也意味着要考虑pepper泄露的可能性。如果只是用pepper对密码进行哈希,那么一旦pepper泄露,无法从哈希后的结果反解得到之前bcrypt哈希过的密码值。作为一个替代方案,Dropbox使用了AES256加密算法。AES256算法提供了差不多的安全性,同时还可以反解回原来的值。尽管AES256这个加密函数的输入是随机的,Dropbox还是额外加上了一个随机的初始化向量(IV)来增强安全性。下一步,Dropbox考虑将pepper存储到一个硬件安全模块(HSM),这虽然是一个相当复杂的任务,但是它能极大的降低pepper泄露的风险。同时,也计划在下一次升级中增强Bcrypt的强度。

展望

Dropbox相信使用SHA512,加上bcrypt和AES256是当前保护密码最稳妥和流行的方法之一。同时,所谓道高一尺魔高一丈。密码哈希程序只是加固Dropbox的众多举措之一,Dropbox还部署了额外的保护措施-比如针对暴力攻击者密码尝试次数的速度限制,验证码,以及其他一些方法等。

原文链接:

发表评论

邮箱地址不会被公开。 必填项已用*标注