Credential stuffing — trying passwords leaked from other services against this login — exploits the basic weakness of a system where a matching password alone is enough. I reproduced it and verified, with the real open-source pentesting tool hydra, how MFA stops it.
A learning resource for backend developers building login systems that assume a matching password alone is enough.
A vulnerable login API that authenticates on a matching password alone.
// Vulnerable login API — a matching password is the whole check.
// A leaked-password list from another breach, tried here as-is,
// gets through (verified directly with hydra).
class PasswordOnlyLogin {
constructor(userDb) {
this.db = userDb; // { username: password }
}
login(username, password) {
if (this.db[username] === password) {
return { status: 'ok' };
}
return { status: 'invalid_credentials' };
}
}
module.exports = { PasswordOnlyLogin };
The fix: a matching password alone is no longer enough without a valid second factor.
// The fix: BOTH the password AND a second factor (TOTP-style) are
// required. Even a 100% correct leaked password is useless to an
// attacker who doesn't have the code that changes in real time.
class MfaGuardedLogin {
constructor(userDb, totpProvider) {
this.db = userDb;
this.totp = totpProvider; // .currentCode(username)
}
login(username, password, totpCode) {
if (this.db[username] !== password) {
return { status: 'invalid_credentials' };
}
if (totpCode !== this.totp.currentCode(username)) {
return { status: 'invalid_credentials' }; // never reveal which part was wrong
}
return { status: 'ok' };
}
}
module.exports = { MfaGuardedLogin };
Questions or feedback about this product? Leave your email if you'd like a reply (optional).