题 用于散列密码字段的数据类型和长度是多少?


我不确定密码哈希是如何工作的(将在以后实现),但现在需要创建数据库模式。

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

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


228
2017-10-29 15:44


起源


另见Openwall's PHP密码哈希框架 (PHPass)。它的便携性和硬化能够抵御一些对用户密码的常见攻击。编写框架的人(SolarDesigner)就是那个写作的人 开膛手约翰 并作为法官坐在 密码哈希竞赛。所以他对密码攻击了解了一两件事。 - jww
请不要在密码上加上限制。您正在对它们进行散列,没有存储上限的存储原因。如果您担心使用密码哈希的DoS攻击,则1000或1024是合理的上限。 - Iiridayn
为什么限制密码长度?至少让用户创建一个100个字符的密码:) - Andrew
对于密码来说,4个字符是一个非常危险的下限,因为这些字符很容易破解。至少使用8但是14或16要好得多。 - quikchange


答案:


这取决于您使用的散列算法。无论输入如何,散列总是产生相同长度的结果。通常将文本中的二进制哈希结果表示为一系列十六进制数字。或者你可以使用 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)

NIST建议使用SHA-256或更高版本的密码。较小的散列算法有其用途,但它们是 已知是可裂缝的

你应该  您在应用散列函数之前的密码。 Salting密码不会影响散列结果的长度。


401
2017-10-29 17:12



@Hippo:请不要使用用户名作为盐。为每个用户生成随机盐。 - Bill Karwin
是的,没有理由不把它存放在同一行。即使攻击者获得了访问您数据库的权限,他们也必须根据该盐构建彩虹表。这就像猜测密码一样多。 - Bill Karwin
@SgtPooki:您需要另一列来以明文形式存储盐。然后,您可以在键入时使用相同的salt对用户的密码进行哈希处理,并将结果与​​存储在表中的哈希摘要进行比较。 - Bill Karwin
如果您将salt存储在同一个表(或具有相同访问权限的任何其他位置)中,则没有理由不将用户名用作salt,因为它对每个用户来说都是唯一的。但是,任何已知的盐都会使哈希密码弱于没有已知盐的哈希值。如果盐也是未知的,盐只会增加价值。 - fijiaaron
我不明白已知与未知盐的交易。如果您正在实现一个站点 - 需要知道正在测试密码的登录页面/脚本/服务的salt。那么 - 你是“未知”的盐倡导者 - 你是否认为攻击者不知道登录过程的代码?否则 - 攻击者不会 总是 知道盐,它是随机的,独特的,与散列密码一起存储还是分开? - mattstuehler


实际上,您可以使用CHAR(哈希长度)来定义MySQL的数据类型,因为每个哈希算法总是会计算出相同数量的字符。例如,SHA1始终返回40个字符的十六进制数。


15
2017-10-29 15:53





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


8
2017-10-29 15:47



'或者MySQL调用它' - MYSQL称之为CHAR。此类型用于固定长度值。所以我认为CHAR比VARCHAR更好。 - Alex B


您可能会在维基百科上找到有关盐析的文章 合算。我们的想法是添加一组数据来随机化您的哈希值;如果有人未经授权访问密码哈希,这将保护您的密码免受字典攻击。


7
2017-10-29 15:50



这确实非常值得(+1),但它没有回答这个问题! (-1) - Bill Karwin
是的,但在这方面绝对相关(+1) - Treb
好点,但更多的评论而不是答案 - MikeT


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


3
2017-10-29 15:59



正义在这里是完全正确的--MySQL会将这些作为数值存储,并且会使这个列的搜索比进行字符串匹配更有效,但盐不应该存储在盐水数据旁边的数据库中 - 这会消除盐提供的安全性。 - Tony Maro
盐是 不 秘密。该 只要 秘密是密码。只需确保每个新密码都有新的密码。每次用户更改密码时,系统都应为该密码生成新的盐。盐应该是长且随机的,例如从加密安全的PRNG生成的16个字节。 - yfeldblum
@TonyMaro不确定SQL级别上的密码字符串是否匹配是一个好策略。换句话说,您不应该在数据库中搜索密码,而是根据用户名检索用户并在代码中比较密码,而不是SQL。 - bart


这实际上取决于您正在使用的散列算法。如果我没记错的话,密码的长度与哈希的长度关系不大。查看您正在使用的散列算法的规范,运行一些测试,并在其上方截断。


2
2017-10-29 15:54





对于md5 vARCHAR(32)是合适的。对于那些使用AES更好地使用varbinary。


2
2018-05-29 07:05





我总是测试找到加密字符串的MAX字符串长度,并将其设置为VARCHAR类型的字符长度。根据您将拥有的记录数量,它可以真正帮助数据库大小。


1
2017-10-29 15:48





你应该用 TEXT (为了向前兼容性而存储无限数量的字符)。哈希算法(需要)随着时间的推移变得更强,因此这个数据库领域需要随着时间的推移支持更多的字符。此外,根据您的迁移策略,您可能需要在同一字段中存储新旧哈希,因此不建议将长度固定为一种类型的哈希。


1
2017-07-25 22:32