我应该使用什么列types/长度来存储数据库中的Bcrypt哈希密码?

我想在数据库中存储散列密码(使用BCrypt)。 对于这种情况来说,这将是一个好的types,哪个是正确的长度? 密码与BCrypt总是相同的长度?

编辑

哈希示例:

$2a$10$KssILxWNR6k62B7yiX0GAe2Q7wwHlrzhF3LqtVvpyvHZf0MwvNfVu

散列一些密码后,似乎BCrypt总是产生60个字符散列。

编辑2

对不起,没有提到的实施。 我正在使用jBCrypt 。

bcrypt的模块化crypt格式由

  • $2$$2a$$2y$标识哈希algorithm和格式,
  • 表示成本参数的两位数字值,后跟$
  • 一个长度为53个字符的base-64编码值(它们使用不同于标准Base 64 Encoding字母表的字母表, ./0AZaz
    • 盐的22个字符(实际上只有132个解码位中的128位)
    • encryption输出的31个字符(有效地仅有186个解码比特中的184个比特)

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

在使用2a格式时,您需要60个字节。 因此,对于MySQL,我build议使用CHAR(60) BINARYBINARY(60) (请参阅_bin二进制sorting以获取关于差异的信息)。

CHAR不是二进制安全的,并且相等不仅仅取决于字节值,而是取决于实际的归类; 在最坏的情况下, A被视为等于a 。 有关更多信息,请参阅_binbinarysorting规则 。

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

正如其他答案所示, BINARY(60)是最简单也是最自然的select,但是如果要最大限度地提高存储效率,则可以通过无损地解构哈希来节省20个字节。 我已经更详细地logging在GitHub: https : //github.com/ademarre/binary-mcf

Bcrypt哈希遵循一种称为模块化encryption格式(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实现 。

我不认为有任何整洁的技巧,你可以做这样的存储,你可以做例如一个MD5哈希。

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

如果您使用PHP的password_hash()PASSWORD_DEFAULTalgorithm来生成bcrypt哈希(我认为这是很大比例的阅读此问题的人),请务必记住,将来password_hash()可能使用不同的algorithm作为默认值,因此可能会影响哈希的长度(但不一定会更长)。

从手册页:

请注意,这个常量是随着时间的推移而改变的,因为新的和更强大的algorithm被添加到PHP中。 出于这个原因,使用这个标识符的结果的长度会随着时间而改变。 因此, build议将结果存储在可扩展超过60个字符的数据库列中 (255个字符将是一个不错的select)。

使用bcrypt,即使你有10亿用户(即你现在正在与facebook竞争)来存储255字节的密码哈希值,也只会有255GB的数据量 – 关于小型SSD硬盘的大小。 存储密码散列将成为应用程序的瓶颈是非常不可能的。 然而,由于某些原因存储空间确实个问题,您可以使用PASSWORD_BCRYPT来强制password_hash()使用bcrypt,即使这不是默认值。 只要确保随时了解bcrypt中发现的任何漏洞,并在每次发布新的PHP版本时查看发行说明。 如果默认algorithm被改变了,那么回顾一下为什么并且做出一个明智的决定是否使用新的algorithm是很好的。