我将对此提供一个略有不同的看法。
我总是把盐和咸密码散列混合在一起存储。
例如,我将把盐的前一半放在密码的盐散列之前,把盐的后一半放在密码的盐散列之后。应用程序知道这种设计,因此可以获取该数据,并获得salt和salt -password散列。
我采用这种方法的理由是:
如果密码/散列数据被泄露并落入攻击者之手,攻击者将不会通过查看数据知道盐是什么。通过这种方式,攻击者实际上无法执行暴力攻击来获得与哈希匹配的密码,因为他不知道哈希的起始位置,也无法知道数据的哪些部分是盐的一部分,哪些是盐密码哈希的一部分(除非他知道应用程序的身份验证逻辑)。
如果加盐密码哈希是按原样存储的,那么可以执行暴力攻击来获得一个密码,该密码在加盐和哈希时产生与加盐密码哈希相同的数据。
然而,例如,即使咸化密码哈希按原样存储,但预先挂起了一个随机字节,只要攻击者不知道第一个字节将被丢弃,这也会增加攻击的难度。您的应用程序将知道在用于身份验证用户时丢弃数据的第一个字节。
结论是…
1)永远不要以完全相同的形式存储身份验证应用程序使用的数据。
2)如果可能的话,保持身份验证逻辑的秘密以增加安全性。
更进一步。
如果您不能对应用程序的身份验证逻辑保密,那么很多人都知道您的数据是如何存储在数据库中的。假设您决定将盐腌密码散列与盐腌密码散列混合存储在一起,其中一些盐腌密码散列在盐腌密码散列前面,其余的盐腌密码散列后面。
在生成随机盐时,您还可以随机决定在咸化密码散列之前/之后存储盐的比例。
例如,生成512字节的随机salt。您将salt附加到密码,并获得您的salt密码的SHA-512哈希值。您还生成一个随机整数200。然后存储salt的前200个字节,然后是咸化密码散列,然后是salt的其余部分。
When authenticating a user's password input, your application will pass over the string, and assume the first 1 byte of the data is the first 1 byte of the salt, followed by the salted-hash. This pass will fail. The application will continue by using the first 2 bytes of the data as the first 2 bytes of the salt, and repeat until a positive result is found after using the first 200 bytes as the first 200 bytes of the salt. If the password is wrong, the application will continue to try all permutations until none are found.
这种方法的优点:
增加了安全性——即使您的身份验证逻辑是已知的,但在编译时,确切的逻辑是未知的。几乎不可能执行蛮力攻击,即使知道确切的逻辑。增加盐的长度将进一步提高安全性。
这种方法的缺点:
由于精确的逻辑是在运行时推断出来的,因此这种方法是cpu密集型的。盐的长度越长,这种方法的cpu密集度就越高。
验证错误密码将涉及最高的CPU成本。这可能会对合法请求产生反作用,但会增加针对攻击者的安全性。
这种方法可以通过多种方式实现,并且可以通过使用变宽盐和/或盐密码散列来使其更加安全。