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

时间:2022-10-18 00:08:54

I want to store a hashed password (using BCrypt) in a database. What would be a good type for this, and which would be the correct length? Are passwords hashed with BCrypt always of same length?

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

EDIT

编辑

Example hash:

示例散列:

$2a$10$KssILxWNR6k62B7yiX0GAe2Q7wwHlrzhF3LqtVvpyvHZf0MwvNfVu

2美元10美元KssILxWNR6k62B7yiX0GAe2Q7wwHlrzhF3LqtVvpyvHZf0MwvNfVu美元

After hashing some passwords, it seems that BCrypt always generates 60 character hashes.

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

EDIT 2

编辑2

Sorry for not mentioning the implementation. I am using jBCrypt.

很抱歉没有提到实现。我用jBCrypt。

4 个解决方案

#1


305  

The modular crypt format for bcrypt consists of

bcrypt模块格式包括

  • $2$, $2a$ or $2y$ identifying the hashing algorithm and format
  • $2$、$2a$或$2y$标识哈希算法和格式
  • a two digit value denoting the cost parameter, followed by $
  • 一个两位数的值表示成本参数,后面是$。
  • a 53 characters long base-64-encoded value (they use the alphabet ., /, 09, AZ, az that is different to the standard Base 64 Encoding alphabet) consisting of:
    • 22 characters of salt (effectively only 128 bits of the 132 decoded bits)
    • 盐的22个字符(实际上只有132个解码位中的128位)
    • 31 characters of encrypted output (effectively only 184 bits of the 186 decoded bits)
    • 31个加密输出字符(实际上186个解码位中只有184位)
  • 53个字符长Base - 64编码值(他们使用字母表。,/ 0 - 9,a - z、a - z不同标准Base 64编码字母)组成的:22个字符的盐(实际上只有128位的128解码比特)31个字符加密输出(实际上只有184位的184解码比特)

Thus the total length is 59 or 60 bytes respectively.

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

As you use the 2a format, you’ll need 60 bytes. And thus for MySQL I’ll recommend to use the CHAR(60) BINARYor BINARY(60) (see The _bin and binary Collations for information about the difference).

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

CHAR is not binary safe and equality does not depend solely on the byte value but on the actual collation; in the worst case A is treated as equal to a. See The _bin and binary Collations for more information.

CHAR并不是二进制安全的,等式并不仅仅取决于字节值,而是取决于实际的排序;在最坏的情况下,A被视为等于A。请参阅_bin和二进制排序以获得更多信息。

#2


44  

A Bcrypt hash can be stored in a BINARY(40) column.

Bcrypt散列可以存储在二进制(40)列中。

BINARY(60), as the other answers suggest, is the easiest and most natural choice, but if you want to maximize storage efficiency, you can save 20 bytes by losslessly deconstructing the hash. I've documented this more thoroughly on GitHub: https://github.com/ademarre/binary-mcf

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

Bcrypt hashes follow a structure referred to as modular crypt format (MCF). Binary MCF (BMCF) decodes these textual hash representations to a more compact binary structure. In the case of Bcrypt, the resulting binary hash is 40 bytes.

Bcrypt散列遵循模块化加密格式(MCF)的结构。二进制MCF (BMCF)将这些文本哈希表示解码为更紧凑的二进制结构。对于Bcrypt,产生的二进制哈希是40字节。

Gumbo did a nice job of explaining the four components of a Bcrypt MCF hash:

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

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

Decoding to BMCF goes like this:

对BMCF的解码是这样的:

  1. $<id>$ can be represented in 3 bits.
  2. $ $可以用3位表示。
  3. <cost>$, 04-31, can be represented in 5 bits. Put these together for 1 byte.
  4. $, 04-31,可以用5位表示。把这些放在一起,一个字节。
  5. The 22-character salt is a (non-standard) base-64 representation of 128 bits. Base-64 decoding yields 16 bytes.
  6. 22字符的salt是128位(非标准)的base-64表示。Base-64解码产生16字节。
  7. The 31-character hash digest can be base-64 decoded to 23 bytes.
  8. 31个字符的散列摘要可以解码为23字节的base-64。
  9. Put it all together for 40 bytes: 1 + 16 + 23
  10. 把它全部放在一起40个字节:1 + 16 + 23。

You can read more at the link above, or examine my PHP implementation, also on GitHub.

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

#3


18  

If you are using PHP's password_hash() with the PASSWORD_DEFAULT algorithm to generate the bcrypt hash (which I would assume is a large percentage of people reading this question) be sure to keep in mind that in the future password_hash() might use a different algorithm as the default and this could therefore affect the length of the hash (but it may not necessarily be longer).

如果您使用的是PHP的password_hash()与PASSWORD_DEFAULT算法生成bcrypt散列(我认为这是一个大部分人阅读这个问题),一定要记住,将来password_hash()可能会使用不同的算法作为默认,因此这可能影响散列的长度(但不一定是长)。

From the manual page:

从手动页面:

Note that this constant is designed to change over time as new and stronger algorithms are added to PHP. For that reason, the length of the result from using this identifier can change over time. Therefore, it is recommended to store the result in a database column that can expand beyond 60 characters (255 characters would be a good choice).

注意,随着新的和更强的算法加入到PHP中,这个常量会随着时间的推移而改变。由于这个原因,使用这个标识符的结果的长度会随时间而变化。因此,建议将结果存储在一个数据库列中,该列可以扩展到60个字符(255个字符将是一个不错的选择)。

Using bcrypt, even if you have 1 billion users (i.e. you're currently competing with facebook) to store 255 byte password hashes it would only ~255 GB of data - about the size of a smallish SSD hard drive. It is extremely unlikely that storing the password hash is going to be the bottleneck in your application. However in the off chance that storage space really is an issue for some reason, you can use PASSWORD_BCRYPT to force password_hash() to use bcrypt, even if that's not the default. Just be sure to stay informed about any vulnerabilities found in bcrypt and review the release notes every time a new PHP version is released. If the default algorithm is ever changed it would be good to review why and make an informed decision whether to use the new algorithm or not.

使用bcrypt,即使您有10亿用户(也就是说,您正在与facebook竞争)来存储255字节的密码哈希,它也只能存储约255 GB的数据——大约相当于一个小型SSD硬盘的大小。在应用程序中存储密码散列将成为瓶颈是非常不可能的。但是,由于某些原因,存储空间确实是一个问题,您可以使用PASSWORD_BCRYPT来强制password_hash()使用bcrypt,即使这不是默认情况。只要确保随时了解bcrypt中发现的任何漏洞,并在每次发布新的PHP版本时查看发布说明。如果修改了默认算法,那么最好检查一下原因,然后做出是否使用新算法的明智决定。

#4


16  

I don't think that there are any neat tricks you can do storing this as you can do for example with an MD5 hash.

我不认为有什么简单的方法可以像存储MD5哈希那样进行存储。

I think your best bet is to store it as a CHAR(60) as it is always 60 chars long

我认为你最好把它存储为CHAR(60),因为它通常是60个字符长。

#1


305  

The modular crypt format for bcrypt consists of

bcrypt模块格式包括

  • $2$, $2a$ or $2y$ identifying the hashing algorithm and format
  • $2$、$2a$或$2y$标识哈希算法和格式
  • a two digit value denoting the cost parameter, followed by $
  • 一个两位数的值表示成本参数,后面是$。
  • a 53 characters long base-64-encoded value (they use the alphabet ., /, 09, AZ, az that is different to the standard Base 64 Encoding alphabet) consisting of:
    • 22 characters of salt (effectively only 128 bits of the 132 decoded bits)
    • 盐的22个字符(实际上只有132个解码位中的128位)
    • 31 characters of encrypted output (effectively only 184 bits of the 186 decoded bits)
    • 31个加密输出字符(实际上186个解码位中只有184位)
  • 53个字符长Base - 64编码值(他们使用字母表。,/ 0 - 9,a - z、a - z不同标准Base 64编码字母)组成的:22个字符的盐(实际上只有128位的128解码比特)31个字符加密输出(实际上只有184位的184解码比特)

Thus the total length is 59 or 60 bytes respectively.

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

As you use the 2a format, you’ll need 60 bytes. And thus for MySQL I’ll recommend to use the CHAR(60) BINARYor BINARY(60) (see The _bin and binary Collations for information about the difference).

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

CHAR is not binary safe and equality does not depend solely on the byte value but on the actual collation; in the worst case A is treated as equal to a. See The _bin and binary Collations for more information.

CHAR并不是二进制安全的,等式并不仅仅取决于字节值,而是取决于实际的排序;在最坏的情况下,A被视为等于A。请参阅_bin和二进制排序以获得更多信息。

#2


44  

A Bcrypt hash can be stored in a BINARY(40) column.

Bcrypt散列可以存储在二进制(40)列中。

BINARY(60), as the other answers suggest, is the easiest and most natural choice, but if you want to maximize storage efficiency, you can save 20 bytes by losslessly deconstructing the hash. I've documented this more thoroughly on GitHub: https://github.com/ademarre/binary-mcf

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

Bcrypt hashes follow a structure referred to as modular crypt format (MCF). Binary MCF (BMCF) decodes these textual hash representations to a more compact binary structure. In the case of Bcrypt, the resulting binary hash is 40 bytes.

Bcrypt散列遵循模块化加密格式(MCF)的结构。二进制MCF (BMCF)将这些文本哈希表示解码为更紧凑的二进制结构。对于Bcrypt,产生的二进制哈希是40字节。

Gumbo did a nice job of explaining the four components of a Bcrypt MCF hash:

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

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

Decoding to BMCF goes like this:

对BMCF的解码是这样的:

  1. $<id>$ can be represented in 3 bits.
  2. $ $可以用3位表示。
  3. <cost>$, 04-31, can be represented in 5 bits. Put these together for 1 byte.
  4. $, 04-31,可以用5位表示。把这些放在一起,一个字节。
  5. The 22-character salt is a (non-standard) base-64 representation of 128 bits. Base-64 decoding yields 16 bytes.
  6. 22字符的salt是128位(非标准)的base-64表示。Base-64解码产生16字节。
  7. The 31-character hash digest can be base-64 decoded to 23 bytes.
  8. 31个字符的散列摘要可以解码为23字节的base-64。
  9. Put it all together for 40 bytes: 1 + 16 + 23
  10. 把它全部放在一起40个字节:1 + 16 + 23。

You can read more at the link above, or examine my PHP implementation, also on GitHub.

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

#3


18  

If you are using PHP's password_hash() with the PASSWORD_DEFAULT algorithm to generate the bcrypt hash (which I would assume is a large percentage of people reading this question) be sure to keep in mind that in the future password_hash() might use a different algorithm as the default and this could therefore affect the length of the hash (but it may not necessarily be longer).

如果您使用的是PHP的password_hash()与PASSWORD_DEFAULT算法生成bcrypt散列(我认为这是一个大部分人阅读这个问题),一定要记住,将来password_hash()可能会使用不同的算法作为默认,因此这可能影响散列的长度(但不一定是长)。

From the manual page:

从手动页面:

Note that this constant is designed to change over time as new and stronger algorithms are added to PHP. For that reason, the length of the result from using this identifier can change over time. Therefore, it is recommended to store the result in a database column that can expand beyond 60 characters (255 characters would be a good choice).

注意,随着新的和更强的算法加入到PHP中,这个常量会随着时间的推移而改变。由于这个原因,使用这个标识符的结果的长度会随时间而变化。因此,建议将结果存储在一个数据库列中,该列可以扩展到60个字符(255个字符将是一个不错的选择)。

Using bcrypt, even if you have 1 billion users (i.e. you're currently competing with facebook) to store 255 byte password hashes it would only ~255 GB of data - about the size of a smallish SSD hard drive. It is extremely unlikely that storing the password hash is going to be the bottleneck in your application. However in the off chance that storage space really is an issue for some reason, you can use PASSWORD_BCRYPT to force password_hash() to use bcrypt, even if that's not the default. Just be sure to stay informed about any vulnerabilities found in bcrypt and review the release notes every time a new PHP version is released. If the default algorithm is ever changed it would be good to review why and make an informed decision whether to use the new algorithm or not.

使用bcrypt,即使您有10亿用户(也就是说,您正在与facebook竞争)来存储255字节的密码哈希,它也只能存储约255 GB的数据——大约相当于一个小型SSD硬盘的大小。在应用程序中存储密码散列将成为瓶颈是非常不可能的。但是,由于某些原因,存储空间确实是一个问题,您可以使用PASSWORD_BCRYPT来强制password_hash()使用bcrypt,即使这不是默认情况。只要确保随时了解bcrypt中发现的任何漏洞,并在每次发布新的PHP版本时查看发布说明。如果修改了默认算法,那么最好检查一下原因,然后做出是否使用新算法的明智决定。

#4


16  

I don't think that there are any neat tricks you can do storing this as you can do for example with an MD5 hash.

我不认为有什么简单的方法可以像存储MD5哈希那样进行存储。

I think your best bet is to store it as a CHAR(60) as it is always 60 chars long

我认为你最好把它存储为CHAR(60),因为它通常是60个字符长。