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

hel*_*hod 295 mysql hash storage types bcrypt

我想在数据库中存储散列密码(使用BCrypt).什么是好的类型,哪个是正确的长度?密码是否与BCrypt长度相同?

编辑

示例哈希:

$2a$10$KssILxWNR6k62B7yiX0GAe2Q7wwHlrzhF3LqtVvpyvHZf0MwvNfVu

在对一些密码进行哈希处理之后,似乎BCrypt总是生成60个字符的哈希值.

编辑2

很抱歉没有提及实施.我正在使用jBCrypt.

Gum*_*mbo 348

bcrypt的模块化密码格式包括

  • $2$,$2a$$2y$识别哈希算法和格式
  • 表示成本参数的两位数值,后跟 $
  • 一个53个字符长的基64编码的值(它们使用的字母表.,/,0- 9,A- Z,a- z也就是不同的标准Base 64编码字母表)由以下组成:
    • 盐的22个字符(实际上只有132个解码位的128位)
    • 加密输出的31个字符(实际上只有186个解码位的184位)

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

当您使用2a格式时,您将需要60个字节.因而对于MySQL的,我会建议使用CHAR(60) BINARYBINARY(60)(见_bin二进制排序规则有关的差异信息).

CHAR不是二进制安全的,并且不仅仅依赖于字节值而是依赖于实际的整理; 在最坏的情况下A被视为等于a.有关更多信息,请参阅The _binand binaryCollat​​ions.

  • 请注意 - 存储为二进制(60)可能会导致字符串相等的意外行为(以及其他内容).在.NET中,这可以通过使用String.Equals(fromDataBaseBinary60string,typicalishString,StringComparison.InvariantCulture)来克服. (27认同)
  • 如果将列定义为CHAR(60)CHARACTER SET latin1 COLLATE latin1_bin,您现在可以获得准确字符串比较的优势,而无需二进制列. (7认同)
  • 人们不应该比较哈希值来进行密码检查。我遇到的每个 bcrypt 库也都有密码检查功能。可以将密码存储为字符串(即使用 CHAR 或 VARCHAR 或 VARCHAR2 的字符数组),并使用库的密码检查函数将该字符串与用户提供的密码进行比较。 (4认同)
  • @AndreFigueiredo`SQL_Latin1_General_CP1_CS_AS`在MySQL中是未知的.众所周知的是`latin1_general_cs`. (2认同)
  • 我不清楚我们应该存储为不是二进制安全的 `char` 还是具有意外行为的 `binary(60)`..... (2认同)
  • @Neon问题是你可能比较不同的哈希值是相等的.如果您明确指定它是二进制列(或具有正确排序规则的VARCHAR),则不会冒其他地方的风险,更改某些设置,使其不区分大小写.它也使你的意图更加清晰,这通常是一件好事 - 你正在存储二进制数据; 你应该将它存储为二进制数据. (2认同)

And*_*e D 49

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

BINARY(60),正如其他答案所暗示的那样,是最简单和最自然的选择,但如果你想最大化存储效率,你可以通过无损解构哈希来节省20个字节.我在GitHub上更详细地记录了这一点:https://github.com/ademarre/binary-mcf

Bcrypt哈希遵循称为模块化密码格式(MCF)的结构.二进制 MCF(BMCF)将这些文本哈希表示解码为更紧凑的二进制结构.在Bcrypt的情况下,得到的二进制散列是40个字节.

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

$<id>$<cost>$<salt><digest>
Run Code Online (Sandbox Code Playgroud)

对BMCF的解码如下:

  1. $<id>$ 可以用3位表示.
  2. <cost>$,04-31,可以用5位表示.将这些放在一起1个字节.
  3. 22个字符的盐是128位的(非标准)base-64表示.Base-64解码产生16个字节.
  4. 31个字符的散列摘要可以基本64位解码为23个字节.
  5. 把它们放在一起40个字节: 1 + 16 + 23

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

  • 更长的字段成本:20字节甚至一百万+记录:20MB,一旦达到一百万条记录+.在高度复杂的安全和工程领域中不正确地实施缩短的字段长度的成本:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $$$$$$$$$$$$$$$$$$$$$$$$$$你做数学. (43认同)
  • @Kzqai这里没有削弱Bcrypt库安全性的风险.这是一种数据编码,在密码检查之前从存储中检索时会撤消.这不是"不要滚动你自己的加密"领域. (11认同)
  • 你的例子充满了我的观点.---如果要将数据库放入内存,请在触摸bcrypt存储列之前优化所有其他列.---如果你已经将每个其他列优化为疯狂度,并且只剩下bcrypt哈希列,则只为bcrypt获取另一个内存.---如果你已经完成了上述两个......停止,你还没有优化其他每一个低悬的水果,你就要乱用一个有效的加密安全系统,并取而代之它有一个更复杂的本土系统,有可能实现失败. (8认同)
  • @Kzqai,就像我说的那样,更大的60字节列是最自然的选择,但追求存储效率的积极性取决于项目.例如,尝试将整个数据库安装在内存中是很常见的,这里20 MB,另外20个可以在内存受限的环境中快速添加. (6认同)

Mik*_*ike 21

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

从手册页:

请注意,此常量旨在随着时间的推移而变化,因为新的和更强大的算法被添加到PHP中.因此,使用此标识符的结果长度可能会随时间而变化.因此, 建议将结果存储在数据库列中,该列可以扩展到超过60个字符(255个字符将是一个不错的选择).

使用bcrypt,即使你有10亿用户(即你目前正在与facebook竞争)存储255字节的密码哈希,它只会有~255 GB的数据 - 大约相当于一个小型SSD硬盘的大小.存储密码哈希极不可能成为应用程序的瓶颈.然而,在关闭的机会,存储空间真的出于某种原因的问题,您可以使用PASSWORD_BCRYPT强制password_hash()使用bcrypt,即使这不是默认的.请务必随时了解bcrypt中发现的任何漏洞,并在每次发布新的PHP版本时查看发行说明.如果更改默认算法,最好查看原因并做出是否使用新算法的明智决定.


Jam*_*s C 18

我不认为你可以做的任何巧妙的技巧存储,例如你可以用MD5哈希.

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

  • 没理由金板.如果您使用的软件需要60个字节,则分配60个字节.如果您的软件的未来版本发生了更改,那么您可以在发布该版本时担心它.您不应该自动安装功能更改更新. (14认同)
  • 我认为这是最好的答案。无需像其他答案那样深入了解算法的复杂性。有关二进制、排序规则等的所有细节都应该由正在使用的任何库来处理。60 个字符。这就是答案。 (3认同)