我应该使用什么列types/长度来存储数据库中的Bcrypt哈希密码?
我想在数据库中存储散列密码(使用BCrypt)。 对于这种情况来说,这将是一个好的types,哪个是正确的长度? 密码与BCrypt总是相同的长度?
编辑
哈希示例:
$2a$10$KssILxWNR6k62B7yiX0GAe2Q7wwHlrzhF3LqtVvpyvHZf0MwvNfVu
散列一些密码后,似乎BCrypt总是产生60个字符散列。
编辑2
对不起,没有提到的实施。 我正在使用jBCrypt 。
bcrypt的模块化crypt格式由
-
$2$
,$2a$
或$2y$
标识哈希algorithm和格式, - 表示成本参数的两位数字值,后跟
$
- 一个长度为53个字符的base-64编码值(它们使用不同于标准Base 64 Encoding字母表的字母表,
.
,/
,0
,A
–Z
,a
–z
)- 盐的22个字符(实际上只有132个解码位中的128位)
- encryption输出的31个字符(有效地仅有186个解码比特中的184个比特)
因此总长度分别是59或60个字节。
在使用2a格式时,您需要60个字节。 因此,对于MySQL,我build议使用CHAR(60) BINARY
或BINARY(60)
(请参阅_bin和二进制sorting以获取关于差异的信息)。
CHAR
不是二进制安全的,并且相等不仅仅取决于字节值,而是取决于实际的归类; 在最坏的情况下, A
被视为等于a
。 有关更多信息,请参阅_bin
和binary
sorting规则 。
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是这样的:
-
$<id>$
可以用3位表示。 -
<cost>$
,04-31,可以用5位表示。 把它们放在一起1个字节。 - 22个字符的盐是128位的(非标准)base-64表示。 Base-64解码产生16个字节。
- 31个字符的散列摘要可以被base-64解码为23个字节。
- 把它放在一起40个字节:
1 + 16 + 23
你可以在上面的链接阅读更多,或者在GitHub上检查我的PHP实现 。
我不认为有任何整洁的技巧,你可以做这样的存储,你可以做例如一个MD5哈希。
我认为你最好的select是将它存储为CHAR(60)
因为它总是60个字符长
如果您使用PHP的password_hash()
和PASSWORD_DEFAULT
algorithm来生成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是很好的。