哈希密码字段使用哪种数据类型,长度如何?


268

我不确定密码哈希的工作原理(稍后将实现),但是需要立即创建数据库架构。

我正在考虑将密码限制为4-20个字符,但是据我了解,加密哈希字符串后的长度将不同。

那么,如何将这些密码存储在数据库中呢?


另请参见Openwall的PHP密码哈希框架(PHPass)。它具有可移植性,并且可以抵抗多种常见的用户密码攻击。编写框架的人(SolarDesigner)与编写John The Ripper的人相同,并担任密码哈希竞赛的评委。因此,他知道有关密码攻击的一两件事。
jww

2
请不要对密码设置上限。您正在对它们进行散列,没有存储上限的原因。如果您担心使用密码哈希进行DoS攻击,则将1000或1024是一个合理的上限。
Iiridayn '16

为什么限制密码长度?至少让用户创建一个100个字符的密码:)
安德鲁(Andrew)

4个字符对于密码来说是一个非常危险的下限,因为这些密码很难破解。至少使用8,但最好使用14或16。
quikchange '16

这是一个很老的问题,答案已经过时。有关最新信息,请参见Gilles的答案
kelalaka

Answers:


448

更新:仅使用哈希函数不足以存储密码。您应该阅读Gilles在该主题上的答案,以获取更详细的解释。

对于密码,请使用增强密钥的哈希算法,例如Bcrypt或Argon2i。例如,在PHP中,使用password_hash()函数(默认情况下使用Bcrypt)。

$hash = password_hash("rasmuslerdorf", PASSWORD_DEFAULT);

结果是一个类似于以下内容的60个字符的字符串(但是数字会有所不同,因为它会生成唯一的盐)。

$2y$10$.vGA1O9wmRjrwAVXD98HNOgsNpDczlqm3Jq7KnEd1rVAGv3Fykk1a

使用SQL数据类型CHAR(60)存储Bcrypt哈希的此编码。请注意,此函数不会编码为十六进制数字的字符串,因此我们无法轻松地将其以十六进制形式存储为二进制。

其他散列函数仍具有用途,但不能用于存储密码,因此我将保留原始答案,该答案写于2008年。


这取决于您使用的哈希算法。不管输入如何,散列总是产生相同长度的结果。通常用一系列十六进制数字将二进制哈希结果表示为文本。或者,您可以使用该UNHEX()功能将十六进制数字的字符串减少一半。

  • MD5生成一个128位哈希值。您可以使用CHAR(32)或BINARY(16)
  • SHA-1生成一个160位的哈希值。您可以使用CHAR(40)或BINARY(20)
  • SHA-224生成224位哈希值。您可以使用CHAR(56)或BINARY(28)
  • SHA-256生成256位哈希值。您可以使用CHAR(64)或BINARY(32)
  • SHA-384生成384位哈希值。您可以使用CHAR(96)或BINARY(48)
  • SHA-512生成512位哈希值。您可以使用CHAR(128)或BINARY(64)
  • BCrypt生成依赖于实现的448位哈希值。您可能需要CHAR(56),CHAR(60),CHAR(76),BINARY(56)或BINARY(60)

自2015年起,NIST 建议将SHA-256或更高版本用于需要互操作性的哈希函数的任何应用程序。但是NIST不建议使用这些简单的哈希函数来安全地存储密码。

较小的散列算法有其用途(例如在应用程序内部,而不是用于交换),但众所周知它们是可破解的


47
@河马:请不要使用用户名作为盐。为每个用户生成随机盐。
Bill Karwin

11
是的,没有理由不将其存储在同一行中。即使攻击者可以访问您的数据库,他们也必须基于该盐构建彩虹表。这和猜测密码一样多。
Bill Karwin 2010年

5
@SgtPooki:您需要另一列以纯文本格式存储盐。然后,您可以在用户输入密码时用相同的盐对密码进行哈希处理,然后将结果与存储在表中的哈希摘要进行比较。
比尔·卡温

12
如果将盐存储在同一表(或具有相同访问权限的任何其他位置)中,则没有理由不使用用户名作为盐,因为用户名是唯一的。但是,与没有已知盐相比,任何已知盐都使哈希算法在密码上较弱。盐只有在还未知的情况下才会增加价值。
fijiaaron 2012年

9
我不了解与已知盐和未知盐的交易。如果要实施站点,则需要在测试密码的登录页面/脚本/服务中知道盐。所以-您是“未知的”盐倡导者-您是否假设攻击者未知登录过程的代码?否则-攻击者是否总是知道盐,它是随机的,唯一的,与哈希密码一起存储还是分开存储?
mattstuehler 2013年


10

始终使用密码哈希算法:Argon2scryptbcryptPBKDF2

Argon2赢得了2015年密码哈希竞赛。ScryptbcryptPBKDF2是较旧的算法,现在被认为不那么但从根本上讲还是不错的,因此,如果您的平台尚不支持Argon2,则可以现在使用另一种算法。

切勿将密码直接存储在数据库中。也不要对其进行加密:否则,如果您的站点遭到破坏,攻击者将获得解密密钥,因此可以获得所有密码。密码必须被散列

密码哈希具有从哈希表散列或密码散列不同的特性。切勿在密码上使用普通的密码哈希,例如MD5,SHA-256或SHA-512。密码哈希算法使用salt,它是唯一的(不用于任何其他用户或其他任何人的数据库)。盐是必不可少的,这样攻击者就不能仅预先计算常用密码的哈希值:使用盐,他们必须为每个帐户重新开始计算。密码哈希算法本质上很慢 -尽可能地慢。慢速攻击对您的伤害要比对您的伤害大得多,因为攻击者必须尝试许多不同的密码。有关更多信息,请参见如何安全地对密码进行哈希处理

密码哈希编码四个信息:

  • 使用哪种算法的指标。这对于敏捷性是必要的:加密建议会随时间而变化。您需要能够过渡到新算法。
  • 难度或硬度指示器。该值越高,则需要更多的计算来计算散列。在密码更改功能中,该值应该是常数或全局配置值,但是随着计算机变得越来越快,它应该随时间增加,因此您需要记住每个帐户的值。一些算法只有一个数字值,其他算法那里有更多参数(例如分别调整CPU使用率和RAM使用率)。
  • 盐。由于盐必须是全局唯一的,因此必须为每个帐户存储。应在每次更改密码时随机生成盐。
  • 适当的哈希,即哈希算法中数学计算的输出。

许多库都包含一对函数,可方便地将此信息打包为单个字符串:一个带有算法指示器,硬度指示器和密码,生成随机盐并返回完整的哈希字符串的函数;另一个将密码和完整的哈希字符串作为输入,并返回一个布尔值,指示密码是否正确。没有通用标准,但是通用编码是

$ 算法 $ 参数 $  $ 输出

其中algorithm是一个数字或编码算法的选择一个短字母数字串,parameters是可打印字符串,saltoutput以Base64而不终止被编码=

16个字节足以容纳盐和输出。(例如参见有关Argon2的建议。)以Base64编码,每个21个字符。其他两个部分取决于算法和参数,但是典型的是20–40个字符。总共大约有82个ASCII字符CHAR(82)并且不需要Unicode),如果您认为以后很难扩展该字段,则应在其中添加安全边距。

如果您以二进制格式对哈希进行编码,则算法的哈希值可以减少到1个字节,硬度值可以减少到1-4个字节(如果您对某些参数进行了硬编码),salt和output可以分别减少到16个字节,共37个字节。说40个字节BINARY(40))至少有几个备用字节。请注意,这些是8位字节,不是可打印字符,特别是该字段可以包含空字节。

请注意,哈希的长度与密码的长度完全无关。


9

您可能会发现Wikipedia上有关盐腌的文章值得。这个想法是添加一组数据来随机化您的哈希值。如果有人未经授权访问密码哈希,这将保护您的密码免受字典攻击。


2
这确实是非常值得的(+1),但是并不能回答问题!(-1)
Bill Karwin

3
是的,但在这种情况下绝对有意义(+1)
Treb

7

作为固定长度的字符串(VARCHAR(n)或MySQL调用它)。哈希始终具有固定长度,例如12个字符(取决于您使用的哈希算法)。因此,将20个字符的密码减少为12个字符的哈希,而4个字符的密码也将产生12个字符的哈希。


3
“或者是MySQL称呼它”-MYSQL称它为CHAR。此类型用于固定长度值。因此,我认为CHAR比VARCHAR更好。
t298712383 '16

4

TEXT为了向前兼容,您应该使用(存储不限数量的字符)。随着时间的流逝,散列算法(需要)变得更强大,因此,随着时间的推移,此数据库字段将需要支持更多字符。另外,根据您的迁移策略,您可能需要在同一字段中存储新哈希和旧哈希,因此不建议将长度固定为一种哈希。


3

这实际上取决于您使用的哈希算法。如果我没记错的话,密码的长度与哈希的长度无关。在您使用的哈希算法上查找规格,运行一些测试,然后在其上方截断。


3

哈希是一个位序列(128位,160位,256位等,具体取决于算法)。如果MySQL允许(SQL Server数据类型为binary(n)varbinary(n)),则您的列应为二进制类型,而不是文本/字符类型。您还应该给哈希加盐。盐可能是文本或二进制,并且您将需要相应的列。


正义在这里是完全正确的-MySQL将把它们存储为数值,并使在此列上的搜索比进行字符串匹配更加有效,但是盐不应该在盐化数据旁边存储在数据库中-这消除了盐提供的安全性。
Tony Maro

6
不是秘密。的唯一秘诀是密码。只需确保每个新密码都会得到一个新的提示。每次用户更改密码时,系统都会为该密码生成一个新的盐。盐应该是长且随机的,例如从加密安全的PRNG生成的16个字节。
yfeldblum 2011年

1
@TonyMaro不确定在SQL级别上是否匹配密码字符串是一个好策略。换句话说,您不应在数据库中搜索密码,而应根据用户名检索用户并在代码而不是SQL中比较密码。
巴特

1

我一直在测试以找到加密字符串的最大字符串长度,并将其设置为VARCHAR类型的字符长度。根据您将要拥有的记录数,它确实可以帮助数据库扩大规模。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.