我对密码散列有什么误解?

这是我的理解,一个哈希函数将始终返回相同的结果时,提供相同的数据。 但是我一直在使用libsodium(通过节点钠),这不是发生了什么事情。

我在我的模式中有这个:

UserSchema.pre('save', function(next) { // declare my variables let user = this, buf = Buffer.alloc(sodium.crypto_pwhash_STRBYTES, 'ascii'), passwordBuf = Buffer.from(user.password, 'ascii'), saltedPassBuf, hash; // only hash the password if it has been modified (or is new) if (!user.isModified('password')) return next(); // generate a salt sodium.randombytes_buf(buf, sodium.crypto_pwhash_STRBYTES, 'ascii'); // add salt to the password saltedPassBuf = Buffer.concat([passwordBuf, buf], 128); // hash it separately multiple times // note, i'm not hashing the hash, // I'm hashing the original buffer to see what happens // this has no application in production hash = sodium.crypto_pwhash_str(saltedPassBuf, sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE, sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE); hash2 = sodium.crypto_pwhash_str(saltedPassBuf, sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE, sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE); hash3 = sodium.crypto_pwhash_str(saltedPassBuf, sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE, sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE); // log it to see what I got -- not for production console.log(hash.toString()); console.log(hash2.toString()); console.log(hash3.toString()); // save the salt and the buffer for authentication user.salt = buf; user.password = hash; next(); }); 

我得到三个不同的string与该代码logging。 例如

 $argon2i$v=19$m=32768,t=4,p=1$ayPVQ1X+xNhWmD9S5AUuaw$1mWusk59AebhzOHhl+j5JpvmRI27Pq57XG5zcAB5R4U $argon2i$v=19$m=32768,t=4,p=1$PjTYKpfhh1bZh+MV84Y9kA$9+U33nf6efuugsrz15cEKDa5+rAHgYVA5Kqo4F1G3DE $argon2i$v=19$m=32768,t=4,p=1$Ii8AErmAFc0na9Yi2OgCkw$ySU80Fv9OiOmeT9EV/BWon1Jjck2Lx23nOeCk0wkMPU 

现在每一个的第一部分是相同的,使得我提交的密码部分是相同的(因为它是被哈希的缓冲区的第一部分)。 所以也许是我不明白的缓冲区。

但是如果buf保持不变,为什么saltedPassBuff的其余部分会saltedPassBuff变化?

编辑:当我不小心提交,编辑完成写作的时候还没有写完

除了salt之外, pwhash函数(文档是最小的)最有可能还会添加自己的随机盐,它也包含在结果中供以后使用crypto_pwhash_str_verify进行比较。

还有一个“CPU密集型”方面,可能是一个迭代。 只用一个哈希函数和一个盐没有什么提高安全性。 需要添加CPU密集型组件,如迭代。

关键是要让攻击者花费大量的时间来查找密码。

正如名字所暗示的,产量是腌制的。 这意味着在散列之前将一个随机string添加到密码中,并分别包含在输出值中。

这样做的目的是击败字典攻击 。 通过在散列之前为每个密码添加一个随机string,确保相同的密码散列不同,迫使攻击者分别破解每个密码。