您没有安全地存储密码
推理:加密哈希函数是单向函数。因此,存储哈希密码应该可以防止攻击者计算出它们。
攻击:与前面讨论过的两个问题不同,这个问题通常只与离线攻击有关。许多企业和组织的密码数据库都被盗了。当掌握了被盗密码库和强大的计算能力,攻击者通常可以计算出许多用户的密码。
存储密码的常用方法是使用加密哈希函数,对密码进行哈希处理。如果最终用户选择完全随机的20+字符密码,这种方法将是完美的。例如密码设成:/K`x}x4%(_.C5S^7gMw)。不幸的是,人们很难记住这些密码。如果简单地对密码进行哈希处理,则使用彩虹表攻击就很容易猜到用户选择的典型密码。
阻止彩虹表攻击通常需要在对每个密码进行散列之前添加随机“盐”。“盐”可以与密码一起存储在清除中。不幸的是,加盐的哈希并没有多大帮助。 GPU非常擅长快速计算加盐哈希值。能够访问大量加盐哈希和GPU的攻击者将能够使用暴力破解和字典攻击等攻击合理且快速地猜测到密码。
有太多不安全的密码存储机制,值得专门写篇文章去探讨。不过,我们先来看看您应该如何存储密码。
防御:有两种主要机制可以防止攻击者:一种是使哈希计算更加昂贵,另一种是向哈希添加一些不可估测的东西。
为了使哈希计算更加昂贵,请使用自适应哈希函数或单向密钥派生函数,而不是密码哈希函数来进行密码存储。加密哈希函数的一个特性是它们可以被计算出来;这个属性导致它们不适合用于密码存储。攻击者可以简单地猜测密码并快速散列以查看生成的哈希值是否与密码数据库中的任何内容匹配。
另一方面,自适应哈希函数和单向密钥导出函数具有可配置的参数,这些参数可用于使哈希计算更加资源密集。如果使用得当,它们可以有助于充分减缓离线攻击,以确保您有时间对正在受到攻击的密码数据库做出反应。
这种方法的问题在于,每次要对用户进行身份验证时,都必须自己计算这些哈希值。这会给服务器带来额外负担,并可能使应用程序更容易受到DoS(拒绝服务)攻击。
或者,您可以添加一些不可猜测的密码哈希值。例如,如果要生成一个长随机密钥,将其添加到密码哈希值以及唯一的随机盐,并且稳妥地保护密钥,那么被盗密码数据库对攻击者来说将毫无用处。攻击者需要窃取密码数据库以及能够使用离线攻击计算出用户密码的密钥。当然,这也产生了一个需要解决的非常重要的密钥管理问题。
|