351

我想在数据库中存储一个散列密码(使用 BCrypt)。什么是一个好的类型,哪个是正确的长度?使用 BCrypt 散列的密码是否总是相同的长度?

编辑

示例哈希:

$2a$10$KssILxWNR6k62B7yiX0GAe2Q7wwHlrzhF3LqtVvpyvHZf0MwvNfVu

在对一些密码进行哈希处理后,BCrypt 似乎总是生成 60 个字符的哈希值。

编辑 2

很抱歉没有提到实施。我正在使用jBCrypt

4

4 回答 4

400

bcrypt 的模块化 crypt 格式包括

  • $2$$2a$$2y$识别散列算法和格式
  • 表示成本参数的两位数,后跟$
  • 一个 53 个字符长的 base-64 编码值(它们使用不同于标准 Base 64 编码.字母的字母表, /, 0–<code>9, A–<code>Z, –<code>z ),包括: a
    • 22 个 salt 字符(实际上只有 132 个解码位中的 128 个位)
    • 31 个字符的加密输出(实际上只有 186 个解码位中的 184 个位)

因此总长度分别为 59 或 60 个字节。

当您使用 2a 格式时,您将需要 60 个字节。因此对于 MySQL,我建议使用CHAR(60) BINARYorBINARY(60)(有关差异的信息,请参阅_bin二进制排序规则)。

CHAR不是二进制安全的,相等性不仅仅取决于字节值,还取决于实际的排序规则;在最坏的情况下A被视为等于a。有关详细信息,请参阅The_binbinaryCollat​​ions

于 2011-05-04T11:11:14.097 回答
58

Bcrypt 哈希可以存储在BINARY(40)列中。

BINARY(60),正如其他答案所暗示的那样,是最简单和最自然的选择,但如果您想最大限度地提高存储效率,您可以通过无损解构散列来节省 20 个字节。我在 GitHub 上对此进行了更详尽的记录:https ://github.com/ademarre/binary-mcf

Bcrypt 哈希遵循称为模块化密码格式 (MCF) 的结构。二进制MCF (BMCF) 将这些文本哈希表示解码为更紧凑的二进制结构。在 Bcrypt 的情况下,生成的二进制哈希是 40 字节。

Gumbo 很好地解释了 Bcrypt MCF 哈希的四个组成部分:

$<id>$<cost>$<salt><digest>

解码为 BMCF 如下所示:

  1. $<id>$可以用 3 位表示。
  2. <cost>$, 04-31, 可以用 5 位表示。将这些放在一起 1 个字节。
  3. 22 个字符的盐是 128 位的(非标准)base-64 表示。Base-64 解码产生 16 个字节。
  4. 31 个字符的散列摘要可以 base-64 解码为 23 个字节。
  5. 将它们放在一起 40 个字节:1 + 16 + 23

您可以在上面的链接中阅读更多内容,或者在 GitHub 上查看我的 PHP 实现。

于 2013-05-17T09:09:48.923 回答
27

如果您将 PHPpassword_hash()PASSWORD_DEFAULT算法一起使用来生成 bcrypt 哈希(我假设有很大一部分人会阅读此问题),请务必记住,将来password_hash()可能会使用不同的算法作为默认算法,因此这可能影响哈希的长度(但不一定更长)。

从手册页:

请注意,此常量旨在随着 PHP 中添加新的和更强大的算法而随时间而变化。因此,使用此标识符的结果长度可能会随时间而变化。因此, 建议将结果存储在可以扩展超过 60 个字符的数据库列中(255 个字符将是一个不错的选择)。

使用 bcrypt,即使你有 10 亿用户(即你目前正在与 facebook 竞争)来存储 255 字节的密码哈希,它也只会存储大约 255 GB 的数据——大约是一个小型 SSD 硬盘的大小。存储密码哈希极不可能成为应用程序的瓶颈。但是,如果由于某种原因存储空间确实PASSWORD_BCRYPT一个问题,您可以使用强制password_hash()使用 bcrypt,即使这不是默认设置。请务必随时了解 bcrypt 中发现的任何漏洞,并在每次发布新的 PHP 版本时查看发行说明。如果默认算法发生更改,最好检查原因并做出是否使用新算法的明智决定。

于 2015-07-20T21:30:38.930 回答
22

我不认为您可以使用任何巧妙的技巧来存储它,例如使用 MD5 哈希。

我认为你最好的选择是将它存储为 aCHAR(60)因为它总是 60 个字符长

于 2011-05-04T09:38:23.443 回答