I use this code to login a user. The password is encrypted with bcrypt
and the SALT_ROUNDS
is the same for every user
const user = await User.findOne({email: args.email});
if (!user || !await user.comparePassword(args.password)) throw new Error("User or Password is not correct");
(comparePassword is a mongoose function)
UserSchema.methods.comparePassword = async function (candidatePassword) {
return await bcrypt.compare(candidatePassword, this.password);
};
As you can see, due to short circuiting the if-check can take a different time to execute - which is measurable for the client.
This means, that a client can find out if a certain email uses our services - which is a minor data leak.
I would need a script like this:
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
}
but don't know how to implement it.
One idea would be to create a Dummy User to create the comparePassword
on if !user
, but I am not sure about the upsides/drawbacks of that or if there is a better solution.
Edit: how about I wrap all of this up in a setTimeout
function? It will take 1Sec (or 500ms or something) no matter what.
I came up with this solution:
and measuring performance shows this works
So unless it takes the server 10x the usual time to respond this works.