1

目前我正在使用一种特定的方案来保护密码,我认为我有一些需要改进的地方。该实现是用 Java 编写的,所以我更喜欢使用 SHA-2 512 作为加密形式。

目前我有一个客户端-服务器模型,所以这些事情可能会发生:

  • 客户想要登录,他通过网络使用一次普通的 SHA-2 512 加密发送他的密码。
  • 服务器将密码存储在数据库中,例如 SHA-2_512(SHA-2_512(password) + salt),内部 SHA-2_512(password) 是它通过网络接收的“加密”密码。
  • 密码检查是在服务器端完成的,没有任何东西可以从服务器泄漏,唯一可能的漏洞是如果有人可以读出我认为的 RAM。

我有这些问题:

  • 当想要破解密码时,攻击者通常会创建冲突攻击。然而,碰撞攻击如何足够?如果密码需要用于其他应用程序,如 Outlook.com、Facebook 或其他应用程序(可能使用另一种盐,因为它们与我的应用程序无关),那么碰撞攻击如何足够呢?你不需要真正的密码吗?

  • SHA-2 512 是否已经使用迭代?即使是这样,我是否应该更改我的加密方法以自动使用多次迭代以及首选多少次迭代?我还阅读了有关使用随机迭代次数(在一个范围内)的信息,如何确定性地存储随机因子?

  • 我应该在服务器代码中存储每次迭代的系统机密吗?请参阅http://blog.mozilla.org/webappsec/2011/05/10/sha-512-w-per-user-salts-is-not-enough/。我可以存储一个数组,该数组将为每次迭代保存一个静态机密,第 n 个机密用于第 n 次迭代。没有人可以知道这些秘密,它们被计算一次(我猜是加密一些随机字符串),然后基本上存储在服务器的 RAM 中。

  • 目前我将输入的密码从客户端发送到服务器只是 SHA-2_512(密码),这个过程是否应该改进,如果是,如何改进?我不能使用盐,因为客户没有可用的盐。

问候。

4

1 回答 1

5

TLDR:您需要使用加密通道(例如 TLS)发送密码。考虑使用bcrypt进行密码散列。

SHA-2 512 不是加密算法,它是一种消息摘要算法。加密算法需要密钥和消息来加密。它产生密文。重要的是加密算法有解密算法。

ciphertext = E(key, plaintext);
plaintext = D(key, ciphertext);

消息摘要采用一段明文并生成消息摘要。没有相应的反向机制来获取消息摘要并检索原始消息。也没有密钥。

digest = hash(plaintext);

如果攻击者能够使用散列访问数据库,则攻击者可以通过暴力破解检索原始密码,并尝试使用散列算法进行大量猜测。

digest1 = hash(guess1);
digest2 = hash(guess2);    //repeat with lots of guesses

首先,通过网络发送散列是不安全的。它需要通过 SSL 等安全通信机制发送。如果攻击者可以截获通信中的哈希值,他们就可以计算出原始密码。

哈希冲突与暴力破解密码不同。当两条不同的消息产生相同的消息摘要时,就会导致哈希冲突。

digest1 = hash(plaintext1);
digest2 = hash(plaintext2);
if ( ( plaintext1 != plaintext2 ) && ( digest1 == digest2 ) )  
    // hash collision

SHA-512 没有旨在防止暴力破解的迭代。SHA 算法集旨在提高效率。在散列密码时添加迭代的原因是增加暴力破解密码所需的时间。与拥有数百万个密码的攻击者相比,执行合法登录尝试和执行 100 次迭代的成本很小,每个密码都需要 100 次迭代。添加更多迭代有助于减少提高处理器速度的影响(这将有助于攻击者更快地尝试更多迭代)。

您应该将迭代次数设为针对每个用户存储的可配置限制。因此,您存储每个用户的密码哈希、盐和迭代计数。这意味着将来您可以增加迭代次数以考虑增加的硬件功率。

以明文形式发送 SHA-2 512 并不安全。您应该在加密通道中发送它,例如 SSL。

说了这么多,SHA-2 并非设计为密码散列算法。它是为消息验证而设计的,并且是高效的。考虑使用专门构建的密码哈希算法。一个例子是bcrypt。它被设计成计算困难,并且内置了盐和迭代。

于 2013-05-19T11:53:01.597 回答