在 bcrypt 之前使用 SHA-256 预处理密码?

信息安全 加密 验证 密码 Web应用程序 密码学
2021-08-28 15:52:26

如果他们愿意,我想允许我的 Web 应用程序的用户使用长密码。今天我意识到 bcrypt 的密码长度限制(72 个字符,其余字符被截断)。

我执行以下操作是否安全?我正在使用 PHP。

当前实施:

password_hash($password, PASSWORD_BCRYPT, $options);

有问题的实施:

password_hash(hash('sha256', $password), PASSWORD_BCRYPT, $option);

相关实施的缺点是什么?

我不是加密专家,请指教。

有问题的实现会限制用户可以使用的密码长度吗?如果是这样,限制是多少?

3个回答

一般来说,这会很好。在 bcrypt 中允许使用任意长度的密码甚至是一种相当推荐的方法。

在数学上,您现在在 64 个字符的字符串上使用 bcrypt,其中有 2^256 个可能的值(SHA-256 提供 256 位输出,通常表示为 64 个字符的十六进制字符串)。即使有人预先计算了 SHA-256 中的常用密码,他们也需要通过 bcrypt 运行这些密码以查找给定哈希的实际输入是什么。

主要的潜在缺点是实现缺陷:如果您曾经存储 SHA-256 值,它们的破解速度相对较快,因此攻击者无需花费精力来破解 bcrypt 值。

仍然建议为 bcrypt 步骤保持足够高的迭代计数 - 这不应该对您的处理时间产生任何特别不利的影响,但会使蛮力攻击更加困难。

请参阅应用 bcrypt 之前的预哈希密码以避免限制一般情况下的密码长度。

您建议的实施是安全的。但是请注意记录您对该功能的特殊用法。

请注意,这password_hash将在第一个 NULL 字节处截断密码,因此您不得使用$raw_output=truehash函数的选项。

不要这样做,您将密钥强度限制在比 bcrypt 单独可以接受的要小得多。

请改用此方法(伪代码无效 PHP):

if length($password) > 72 bytes
then
    $hash = sha256($password)
    $password = concat(substring($password, 320 bits), base255encode($hash))
end if
bcrypt($password)

通过这种方式,256 到 576 位之间的密码保留了它们的全部熵,而 576 位以上的密码不仅使用了散列中的 256 位,而且还使用了尽可能多的原始熵。

是否应该对整个密码进行哈希处理,还是只对超过 320 位的部分进行哈希处理是有争议的。当您选择具有良好属性的加密哈希时,我严重怀疑它是否有任何区别。

正如@a-hersean 警告的那样,base255encode 步骤避免了 NUL 字节提前终止密钥。