问题描述
我使用此代码登录用户。密码用 bcrypt
加密,每个用户的 SALT_ROUNDS
都是一样的
const user = await User.findOne({email: args.email});
if (!user || !await user.comparePassword(args.password)) throw new Error("User or Password is not correct");
UserSchema.methods.comparePassword = async function (candidatePassword) {
return await bcrypt.compare(candidatePassword,this.password);
};
如您所见,由于短路,if-check 可能需要不同的时间来执行 - 这对客户来说是可以衡量的。
这意味着,客户可以查明某封电子邮件是否使用了我们的服务——这是一次轻微的数据泄露。
我需要这样的脚本:
const err = new Error("User or Password is not correct.")
if (!user) {
await "wait as long as a password comparison would usually take"
throw err
} else if (!await user.comparePassword(args.password)) {
throw err
}
但不知道如何实现它。
一个想法是创建一个虚拟用户来在 if comparePassword
上创建 !user
,但我不确定它的优点/缺点,或者是否有更好的解决方案。>
编辑:我将所有这些都包含在一个 setTimeout
函数中如何?无论如何都需要 1 秒(或 500 毫秒之类的)。
解决方法
我想出了这个解决方案:
const user = await User.findOne({email: args.email});
const start = performance.now()
const errorToThrow = (!user || !await user.comparePassword(args.password))
const timeElapsed = performance.now() - start
//console.log(`time elapsed: ${timeElapsed}`)
//wait constant time to protect against timing attacks
// OPTIMIZE still able to go for timing attack if `comparePassword` takes >1000ms
await new Promise((resolve) => {
setTimeout(resolve,1000 - timeElapsed);
});
//console.log(`Constant wait time: ${performance.now() - start}`)
if (errorToThrow) throw new Error("User or Password is not correct.")
//generate token
return jwt.sign({
_id: user._id,username: user.name,role: user.role
},process.env.JWT_SECRET,{
expiresIn: "24h"
});
并且衡量性能表明这是有效的
#successful login
time elapsed: 111.46860000118613
Constant wait time: 1008.9731000009924
time elapsed: 77.95830000005662
Constant wait time: 1011.4061999991536
time elapsed: 77.98919999971986
Constant wait time: 1001.5624000001699
time elapsed: 73.09439999982715
Constant wait time: 1000.9662999995053
#user doesnt exist
time elapsed: 0.002399999648332596
Constant wait time: 1015.8186999987811
time elapsed: 0.002199999988079071
Constant wait time: 1006.2013000007719
time elapsed: 0.0023000016808509827
Constant wait time: 1006.3976000007242
time elapsed: 0.0037999991327524185
Constant wait time: 1003.9857000000775
#password incorrect
time elapsed: 74.4993999991566
Constant wait time: 1009.0491999983788
time elapsed: 73.85539999976754
Constant wait time: 1012.3958000000566
time elapsed: 75.48650000058115
Constant wait time: 1014.1987999994308
time elapsed: 71.53899999894202
Constant wait time: 1007.4519999995828
time elapsed: 74.53729999996722
Constant wait time: 1001.8896000012755
所以除非服务器需要 10 倍的时间来响应此工作。