如果我只有一个数据库列,如何存储加盐密码哈希?
我已经阅读了许多关于这个主题的问题,但是我无法理解存储密码的加盐哈希的应用实践。
让我们从一些基本规则开始:
- 密码“foobar12”(我们不讨论密码的强度)。
- 一种语言,本次讨论的 Java 1.6
- 一种数据库,postgreSQL、MySQL、SQL Server、Oracle
有几个选项可用于存储密码,但我想考虑一个 (1):
将使用随机盐散列的密码存储在数据库中,一列
明文存储的自动失败不公开讨论。 :) 在 SO 和其他地方找到了使用 MD5/SHA1 和使用双列的解决方案,两者都有优点和缺点。
MD5/SHA1 很简单。 Java中的MessageDigest提供了MD5、SHA1(通过现代实现中的SHA512,当然是1.6)。此外,列出的大多数 RDBMS 都提供了有关插入、更新等的 MD5 加密功能的方法。一旦人们理解了“彩虹表”和 MD5 冲突(我已经理解了这些概念),问题就会变得明显。
双列解决方案基于这样的想法:盐不需要保密(理解它)。但是,如果您的旧系统只有一 (1) 列用于密码,并且更新表和代码的成本可能太高,那么第二列会带来复杂性,这种复杂性可能并不奢侈。
但它是在单个数据库列中存储用随机盐散列的密码,我需要通过实际应用更好地理解它。
我喜欢这个解决方案有几个原因:需要盐并考虑遗留边界。这就是我迷失的地方:如果盐是随机的,并且密码加盐被散列以生成用于存储的单向值,那么系统如何永远匹配明文密码和新随机盐?
我对此有理论,当我输入时,我可能会理解这个概念:给定 128 字节的随机盐和 8 字节的密码('foobar12') ,通过对随机 128 字节盐进行散列并获取原始散列(即散列密码)的子字符串,可以以编程方式删除散列中作为盐的部分。然后使用哈希算法重新进行哈希匹配...?
所以...任何愿意提供帮助的人。 :) 我很接近吗?
I've read a number of SO questions on this topic, but grokking the applied practice of storing a salted hash of a password eludes me.
Let's start with some ground rules:
- a password, "foobar12" (we are not discussing the strength of the password).
- a language, Java 1.6 for this discussion
- a database, postgreSQL, MySQL, SQL Server, Oracle
Several options are available to storing the password, but I want to think about one (1):
Store the password hashed with random salt in the DB, one column
The automatic fail of plaintext storage is not open for discussion. :) Found on SO and elsewhere are solutions with MD5/SHA1 and use of dual-columns, both with pros and cons.
MD5/SHA1 is simple. MessageDigest in Java provides MD5, SHA1 (through SHA512 in modern implementations, certainly 1.6). Additionally, most RDBMSs listed provide methods for MD5 encryption functions on inserts, updates, etc. The problems become evident once one groks "rainbow tables" and MD5 collisions (and I've grokked these concepts).
Dual-column solutions rest on the idea that the salt
does not need to be secret (grok it). However, a second column introduces a complexity that might not be a luxury if you have a legacy system with one (1) column for the password and the cost of updating the table and the code could be too high.
But it is storing the password hashed with a random salt in single DB column that I need to understand better, with practical application.
I like this solution for a couple of reasons: a salt is expected and considers legacy boundaries. Here's where I get lost: If the salt is random, and the password plus salt are hashed to produced a one-way value for storing, how can the system ever match a plaintext password and a new random salt?
I have theory on this, and as I type I might be grokking the concept: Given a random salt of 128 bytes and a password of 8 bytes ('foobar12'), it could be programmatically possible to remove the part of the hash that was the salt, by hashing a random 128 byte salt and getting the substring of the original hash that is the hashed password. Then re hashing to match using the hash algorithm...?
So... any takers on helping. :) Am I close?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
没有什么大秘密。单列解决方案与多列解决方案类似,只是它将盐和哈希组合到单个列中。检查代码仍然必须知道如何将该单个值分解为盐和散列。 (这就是加盐密码的典型工作方式 - 例如,UNIX
/etc/shadow
格式将算法标识符、加盐和哈希值一起存储在单个字段中)。不过,您不必太担心这一点,因为密码散列算法应该包含执行此操作的智能。例如,如果您使用 jBCrypt,那么您只需:
存储密码时数据库密码列中的BCrypt.hashpw()
; 检查密码时,将There's no great mystery. The single-column solution is just like the multi-column solution, except that it combines the salt and the hash together into a single column. The checking code still has to know how to break that single value down into the salt and hash. (This has been how salted passwords have typically worked - for example, the UNIX
/etc/shadow
format stores an algorithm identifier, salt and hash together in a single field).You don't have to worry about this too much though, because the password hashing algorithm should include the smarts to do this. For example, if you use jBCrypt, then you simply:
BCrypt.hashpw()
in the database password column when storing a password; andBCrypt.checkpw()
when checking a password.您还可以将盐和哈希存储在同一列中(使用分隔符)。
You could also store salt and hash in the same column (using a separator).
您始终必须通过将盐存储在数据库中(正如您在多列解决方案中看到的那样)来了解盐,或者能够以其他方式生成盐(这会破坏随机盐的一些但不是全部点)。
如果您只有一列来存储密码,那么您可以:
在第一种情况下,您可以想出一些简单的函数:
在第二种情况下:
You always have to know the salt, by storing it in the DB (as you saw with multi column solutions) or be able to generate it in some other way (which defeats some, but not all, of the point of random salt).
If you only have a single column in which to store the password, then you can either:
In the first case, you can come up with some trivial function:
In the second:
它通过计算用户输入的密码的哈希值来匹配它,使用相同的盐,它从数据库中读取(与哈希值同时读取)。
It matches it by computing the hash of the password the user entered with the same salt, which it reads from the database (at the same time as the hash).
请参阅 http://www.aspheute.com/english/20040105.asp
用户使用加盐哈希进行身份验证,而不是未加盐的密码或随机盐本身。加盐哈希和盐(但不是实际密码)都存储在数据库中(如果您愿意,可以将它们存储在单列中,但在使用前必须再次将它们分开)。
为了从用户那里恢复加盐哈希(以便您可以将其与存储的加盐哈希进行比较),您需要来自数据库的加盐以及用户提供的密码。
加盐哈希的创建方式如下:
身份验证的完成方式如下:
为每个用户生成一个新的盐。如果两个用户意外选择相同的密码,则两个用户帐户的加盐哈希值仍然不同。
See http://www.aspheute.com/english/20040105.asp
The user is authenticated with a salted hash, not the unsalted password or the random salt by itself. The salted hash and the salt (but not the actual password) are both stored in the database (you can store them in a single column if you like, but you will have to separate them again before use).
In order to recover the salted hash from the user (so that you can compare it to the stored salted hash), you need the salt from the database, and the password provided by the user.
The salted hash is created like this:
Authentication is done like this:
A new salt is generated for each user. Should two users accidentally choose the same password, the salted hash will still be different for both user accounts.