我想在数据库中存储一个散列密码(使用BCrypt)。什么样的类型比较好,什么样的长度比较正确?密码哈希与BCrypt总是相同的长度?
编辑
示例散列:
$2a$10$KssILxWNR6k62B7yiX0GAe2Q7wwHlrzhF3LqtVvpyvHZf0MwvNfVu
在哈希一些密码之后,BCrypt似乎总是生成60个字符的哈希。
编辑2
抱歉没有提到实现。我正在使用jBCrypt。
我不认为有什么巧妙的技巧可以像MD5哈希那样存储它。
我认为你最好的办法是将它存储为CHAR(60),因为它总是60个字符长
CHAR(60)
bcrypt的模块化crypt格式由
$2$
$2a$
$2y$
$
.
/
0
9
A
Z
a
z
因此,总长度分别为59或60字节。
如果使用2a格式,则需要60个字节。因此,对于MySQL,我建议使用__ABC0or BINARY(60)(关于区别的信息,请参阅_bin和二进制排序规则)。
BINARY(60)
CHAR不是二进制安全的,相等性不仅仅取决于字节值,而是取决于实际的排序规则;在最坏的情况下,A被视为等同于a。更多信息见__ABC3和binary排序规则。
CHAR
binary
Bcrypt哈希可以存储在BINARY(40)列中。
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>$
<cost>$
1 + 16 + 23
你可以在上面的链接阅读更多,或检查我的PHP实现,也在GitHub上。
如果你正在使用PHP的password_hash()和PASSWORD_DEFAULT算法来生成bcrypt哈希(我认为阅读这个问题的人占很大比例),一定要记住,在未来password_hash()可能会使用不同的算法作为默认值,因此这可能会影响哈希的长度(但不一定更长)。
password_hash()
PASSWORD_DEFAULT
从手册页:
注意,这个常量被设计为随着时间的推移而改变为新的和 更强大的算法被添加到PHP中。因为这个原因,长度 使用此标识符的结果可以随着时间的推移而改变。因此, 建议将结果存储在可以的数据库列中 扩展到超过60个字符(255个字符将是一个很好的选择)
使用bcrypt,即使你有10亿用户(即你目前正在与facebook竞争)来存储255字节的密码哈希,它也只有~255 GB的数据-大约是一个小型SSD硬盘的大小。存储密码散列不太可能成为应用程序中的瓶颈。然而,如果由于某种原因,存储空间是确实存在问题,则可以使用PASSWORD_BCRYPT强制password_hash()使用bcrypt,即使这不是默认值。只要确保了解在bcrypt中发现的任何漏洞,并在每次发布新的PHP版本时查看发布说明即可。如果默认算法发生了变化,最好检查为什么,并做出是否使用新算法的明智决定。
PASSWORD_BCRYPT
我认为最好的选择是非二元型,因为相比之下组合较少,应该更快。如果使用基数64,那么每个位置,每个字节只有64个可能的值。在十六进制形式中,每个字节只有16个可能的值。在二进制字节中,每个字节有256个位置。 我以编码64 VARCHAR (255)列的形式使用for哈希,具有ascii字符集和相同的排序规则。 VARBINARY会导致MySQL文档中描述的比较问题。我不知道为什么回答使用VARBINARY的建议有这么多积极的方面