在您的情况下,破解哈希算法等同于在哈希算法中找到碰撞。这意味着您不需要找到密码本身(这将是
预像攻击),您只需要找到一个哈希函数的输出,它等于有效密码的哈希值(因此“碰撞”)。使用
生日攻击查找碰撞需要O(2 ^(n / 2))时间,其中n是哈希函数输出长度(以位为单位)。
SHA-2的输出大小为512位,因此查找碰撞需要O(2 ^ 256)时间。假设没有对算法本身的聪明攻击(目前SHA-2哈希系列没有已知的攻击),这就是破解算法所需的时间。
要了解2 ^ 256实际上意味着什么:目前人们认为整个宇宙中的原子数量大约为10 ^ 80,大约为2 ^ 266。假设32字节输入(对于您的情况合理-20字节盐+12字节密码),我的计算机需要约0.22秒(〜2 ^ -2秒)进行65536次计算。因此,2 ^ 256次计算将在2 ^ 240 * 2 ^ 16次计算中完成,这将花费
2^240 * 2^-2 = 2^238 ~ 10^72s ~ 3,17 * 10^64 years
即使称之为数百万年也是荒谬的。而且使用全球最快的硬件并行计算数千个哈希值也无济于事。没有人类技术能够将这个数字转化为可接受的内容。
所以在这里忘记暴力破解SHA-256。你的下一个问题是关于字典单词的。传统上,
彩虹表被用来恢复这种弱密码。彩虹表通常只是预先计算的哈希值表,其思想是,如果您能够预先计算并存储每个可能的哈希值及其输入,则使用O(1)查找给定哈希值并检索有效的预像。当然,在实践中这是不可能的,因为没有存储设备可以存储如此巨大的数据量。这个困境被称为
内存时间权衡。由于只能存储那么多的值,典型的彩虹表包括一些形式的哈希链和中间减少函数(这在维基百科文章中有详细解释),以节省空间但放弃一些时间上的优势。
盐值是一种针对彩虹表的对策。为了防止攻击者为特定盐值预先计算表格,建议采用每个用户的个人盐值。然而,由于用户不使用安全、完全随机的密码,如果盐值已知,您只需在一个简单的试错方案中迭代一个常见密码大字典,仍然会取得意外的成功。自然语言和随机性之间的关系被表示为entropy。典型的密码选择通常具有较低的熵值,而完全随机的值则包含最大的熵值。
典型密码的低熵值使得您的用户中有相当高的机率使用来自相对较小的常见密码数据库中的密码。如果您在谷歌上搜索它们,您会找到这些密码数据库的种子链接,通常属于几十亿字节级别。如果攻击者没有任何限制,使用这样的工具通常需要几分钟到几天的时间才能成功。
这就是通常仅使用哈希和盐值还不够的原因,您还需要安装其他安全机制。您应该使用人工减速的熵诱导方法,例如PKCS#5中描述的PBKDF2,并且应强制要求给定用户在重试输入密码之前等待一段时间。一个好的方案是从0.5秒开始,然后每次失败尝试将时间加倍。在大多数情况下,用户不会注意到这一点,并且平均而言不会经常失败超过三次。但它将显着减缓任何试图攻击您的应用程序的恶意外部人员。