我应该使用什么列类型/长度存储Bcrypt哈希密码在数据库中?

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

编辑

示例散列:

$2a$10$KssILxWNR6k62B7yiX0GAe2Q7wwHlrzhF3LqtVvpyvHZf0MwvNfVu

在哈希一些密码之后,BCrypt似乎总是生成60个字符的哈希。

编辑2

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

169932 次浏览

我不认为有什么巧妙的技巧可以像MD5哈希那样存储它。

我认为你最好的办法是将它存储为CHAR(60),因为它总是60个字符长

bcrypt的模块化crypt格式由

  • $2$$2a$$2y$标识哈希算法和格式
  • 一个表示开销参数的两位数值,后面跟着$
  • 一个53个字符长的base-64编码值(它们使用字母./0 -9A -Za -z,这与标准base64编码字母不同),包括:
    • 盐的22个字符(实际上只有132个解码位中的128位)
    • 加密输出的31个字符(实际上只有186个解码位中的184位)

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

如果使用2a格式,则需要60个字节。因此,对于MySQL,我建议使用__ABC0or BINARY(60)(关于区别的信息,请参阅_bin二进制排序规则)。

CHAR不是二进制安全的,相等性不仅仅取决于字节值,而是取决于实际的排序规则;在最坏的情况下,A被视为等同于a。更多信息见__ABC3和binary排序规则

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

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

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

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

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

解码到BMCF是这样的:

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

你可以在上面的链接阅读更多,或检查我的PHP实现,也在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版本时查看发布说明即可。如果默认算法发生了变化,最好检查为什么,并做出是否使用新算法的明智决定。

我认为最好的选择是非二元型,因为相比之下组合较少,应该更快。如果使用基数64,那么每个位置,每个字节只有64个可能的值。在十六进制形式中,每个字节只有16个可能的值。在二进制字节中,每个字节有256个位置。 我以编码64 VARCHAR (255)列的形式使用for哈希,具有ascii字符集和相同的排序规则。 VARBINARY会导致MySQL文档中描述的比较问题。我不知道为什么回答使用VARBINARY的建议有这么多积极的方面