然而,单独使用这些被认为是安全的哈希函数并不是持久密码的安全技术。针对这些哈希值的两种相关攻击给我们带来了问题。第一种攻击是字典攻击,也称为彩虹表攻击。所有可以想到的输入都被预先计算以用于要攻击的哈希函数,并将其存储在字典中,或者更有效地存储在彩虹表中。如果密码哈希值泄露,攻击者可以在该字典中查找使用了哪个密码。互联网上已经有已知方法的字典,因此我们甚至不必创建字典。第二种攻击是简单的暴力攻击,其中尝试所有输入而不首先创建数据库。这是通过已经提到的经典哈希函数的效率和用户生成的密码的低熵(即分布)来实现的。例如,由于 GPU 可以并行执行大量计算,因此可以使用 hashcat 实现每秒尝试多达 230 亿次 SHA-256 哈希(!)。因此,您可以想象,如果您暴力破解最常用的密码,在大多数情况下,只需几秒钟即可获得适当的纯文本密码。
该会使这些攻击变得更加困难。为了使创建字典对攻击者来说不切实际,密码与公共随机值(盐)相结合。例如,通常将此值附加到密码字符串中。为了进行字典攻击,必须为每种可能的盐创建包含所有可能密码的 外汇电子邮件列表 字典。使用 n 位长盐将需要比不使用盐多 2 的 n 次方的字典。这使得攻击变得不切实际。暴力问题是通过使用人为减慢速度的技术来解决的。这意味着尝试需要更长的时间,因此无法再有效地进行。作为该过程应该和可能花费多长时间的指示,登录后端服务器可能需要 0.5 - 1 秒。
在下面的部分中,我现在将介绍三种不同的方法来提供这些对策,并使用基于 Bouncy Castle 的 Spring Security 的 Java 代码片段来说明它们。
PBKDF2
基于密码的密钥派生函数 2 由 RSA 实验室于 2000 年发布,作为 PKCS#5 规范的一部分。例如,此函数可以从用户生成的密码生成可用于对称加密的密钥。
但它还提供了我们进行密码散列所需的属性。为了阻止上述攻击,首先生成随机盐。该盐与计数器连接,然后多次将密钥哈希消息身份验证代码 (HMAC) 应用于该字符串。 HMAC 生成使用密钥进行身份验证的哈希值,这意味着只有知道密码才能计算出相同的哈希值。 SHA-1 曾经用作内部哈希函数,但现在至少 SHA-256 很常见。该函数还有一个迭代计数器。这决定了重复该过程的频率。这个值越大,执行就越耗费资源,因此暴力攻击就越困难,但登录时的验证也需要更长的时间。通过参数化,随着可用计算能力的发展,可以根据应用程序调整该值。