kelektiv / node.bcrypt.js

bcrypt for NodeJs
MIT License
7.49k stars 517 forks source link

Timing Attack when no user is found in database #1005

Closed Timothy-Pulliam closed 1 year ago

Timothy-Pulliam commented 1 year ago

I know timing attacks have been discussed quite a bit, but I cannot find anything for this specific context.

I have found that the below code runs noticeably quicker when no user is found, since it exits immediately, and no check is done on the hash. This could give an attacker insight into whether a username exists in the database or not. Is there a way to mitigate this using bcrypt.js library?

For example, here are some times when testing.

User does not exist

POST /login 401 11.846 ms - 42

User exists, wrong password

POST /login 401 104.914 ms - 42

router.post('/login', async (req, res) => {
    if (!req.body.email) {
        res.json({ success: false, message: "No email provided" });
    }
    if (!req.body.password) {
        res.json({ success: false, message: "No password provided" });
    }

    const user = await User.findOne({ email: req.body.email });
    // If no user found
    if (!user) {
        return res.status(401).json({ message: 'Invalid username or password' });
    }
    bcrypt.compare(req.body.password, user.password, function (err, result) {
        if (err) {
            console.error(err);
            return res.render('login');
        }
        if (result) {
            console.log("User authenticated successfully");
            return res.redirect('/');
        } else {
            return res.status(401).json({ message: 'Invalid username or password' });
        }
    });
});

More information on OWASP guidelines

https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html#authentication-responses

Timothy-Pulliam commented 1 year ago

Nevermind, I found this article which provides a solution.

https://blog.propelauth.com/understanding-timing-attacks-with-code/