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

EDIT

示例散列:

2a美元,10美元KssILxWNR6k62B7yiX0GAe2Q7wwHlrzhF3LqtVvpyvHZf0MwvNfVu美元

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

编辑2

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


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

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

bcrypt的模块化crypt格式由

$2$, $2a$或$2y$识别哈希算法和格式 表示成本参数的两位数值,后跟$ 一个53个字符长的Base -64编码值(他们使用字母。,/,0-9,a - z, a - z,这与标准的Base 64编码字母不同),包括: 盐的22个字符(实际上只有132个解码位中的128位) 加密输出的31个字符(实际上只有186个解码位中的184位)

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

如果使用2a格式,则需要60个字节。因此,对于MySQL,我建议使用CHAR(60) BINARYor BINARY(60)(参见_bin和BINARY Collations关于差异的信息)。

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

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是这样的:

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

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

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

从手册页:

请注意,这个常量被设计为随着时间的推移而更改为新的和 更强大的算法被添加到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.

I think best choice is nonbinary type, because in comparison is less combination and should be faster. If data is encoded with base64_encode then each position, each byte have only 64 possible values. If encoded with bin2hex each byte have only 16 possible values, but string is much longer. In binary byte have 256 position on each. I use for hashes in form of encode64 VARCHAR(255) column with ascii character set and the same collation. VARBINARY causes comparison problem as described in MySQL documentation. I don't know why answers advice to use VARBINARY have so many positives. I checked this on my author site, where measure time (just refresh to see).