我想在数据库中存储一个散列密码(使用 BCrypt)。什么是一个好的类型,哪个是正确的长度?使用 BCrypt 散列的密码是否总是相同的长度?
编辑
示例哈希:
$2a$10$KssILxWNR6k62B7yiX0GAe2Q7wwHlrzhF3LqtVvpyvHZf0MwvNfVu
在对一些密码进行哈希处理后,BCrypt 似乎总是生成 60 个字符的哈希值。
编辑 2
很抱歉没有提到实施。我正在使用 jBCrypt。
bcrypt 的模块化 crypt 格式包括
$2$、$2a$ 或 $2y$ 标识哈希算法和格式
表示成本参数的两位数字值,后跟 $
一个 53 个字符长的 base-64 编码值(它们使用字母表 .、/、0-9、A-Z、a-z,这与标准 Base 64 编码字母表不同)包括:22 个盐字符(有效132 个解码位中只有 128 位)加密输出的 31 个字符(实际上只有 186 个解码位中的 184 位)
22 个 salt 字符(实际上只有 132 个解码位中的 128 个位)
31 个字符的加密输出(实际上只有 186 个解码位中的 184 个位)
因此总长度分别为 59 或 60 个字节。
当您使用 2a 格式时,您将需要 60 个字节。因此对于 MySQL,我建议使用 CHAR(60) BINARY
or BINARY(60)
(有关差异的信息,请参阅 The _bin and binary Collations)。
CHAR
不是二进制安全的,相等性不仅仅取决于字节值,还取决于实际的排序规则;在最坏的情况下,A
被视为等于 a
。有关详细信息,请参阅 The _bin
and binary
Collations。
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 如下所示:
$
您可以在上面的链接中阅读更多内容,或者查看 my PHP implementation,也可以在 GitHub 上查看。
如果您将 PHP 的 password_hash()
与 PASSWORD_DEFAULT
算法一起使用来生成 bcrypt 哈希(我假设大部分人会阅读此问题),请务必记住,将来 password_hash()
可能会使用不同的算法作为默认值,因此这可能会影响散列的长度(但不一定更长)。
从手册页:
请注意,此常量旨在随着 PHP 中添加新的和更强大的算法而随时间而变化。因此,使用此标识符的结果长度可能会随时间而变化。因此,建议将结果存储在可以扩展超过 60 个字符的数据库列中(255 个字符将是一个不错的选择)。
使用 bcrypt,即使你有 10 亿用户(即你目前正在与 facebook 竞争)来存储 255 字节的密码哈希,它也只会存储大约 255 GB 的数据——大约是一个小型 SSD 硬盘的大小。存储密码哈希极不可能成为应用程序的瓶颈。但是,如果由于某种原因存储空间确实是问题,您可以使用 PASSWORD_BCRYPT
强制 password_hash()
使用 bcrypt,即使这不是默认设置。请务必随时了解 bcrypt 中发现的任何漏洞,并在每次发布新的 PHP 版本时查看发行说明。如果默认算法发生更改,最好回顾一下为什么并做出是否使用新算法的明智决定。
我不认为您可以使用任何巧妙的技巧来存储它,例如使用 MD5 哈希。
我认为您最好的选择是将其存储为 CHAR(60)
因为它总是 60 个字符长
不定期副业成功案例分享
SQL_Latin1_General_CP1_CS_AS
在 MySQL 中是未知的。已知的是latin1_general_cs
。char
还是具有意外行为的binary(60)
.....