据我所知,当输入相同数据时,哈希函数将始终返回相同的结果。但我一直在使用libsodium(通过node-sodium),而这不是正在发生的事情。
我的架构中有这个:
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();
});
我使用该代码记录了三个不同的字符串。例如
$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
的其余部分会发生变化?
编辑:当我不小心提交时编辑完成,编辑完成编写问题
答案 0 :(得分:1)
除了你的盐之外,pwhash
函数(文档是最小的)最有可能还添加了自己的随机盐,它也包含在结果中,以便稍后使用crypto_pwhash_str_verify
进行比较。
还有一个“CPU密集型”方面,可能是迭代。仅使用带有salt的哈希函数几乎不能提高安全性。需要添加CPU密集型组件,例如迭代。
重点是让攻击者花费大量时间通过暴力破解密码。
答案 1 :(得分:0)
顾名思义,输出是盐渍的。这意味着在散列之前将随机字符串添加到密码中,并且还单独包含在输出值中。
这样做的目的是打败dictionary attacks。通过在散列之前向每个密码添加随机字符串,可以确保相同的密码以不同方式散列,从而迫使攻击者单独破解每个密码。