Weak password hashing with MD5

Weak password hashing with MD5

Description

A fast hash such as MD5 lets an attacker test many candidate passwords quickly after a database breach. This is password guessing by comparing hashes, not decryption of the hash. Without a unique salt, attackers can also use precomputed hash lists and compare hashes across users.

Potential impact

  • Rapid offline guessing may reveal users' passwords.
  • Recovered passwords may let an attacker access accounts without permission.

Remediation

  • Do not use fast hashes such as MD5 or SHA-1 for password storage.
  • Use a maintained Argon2id or scrypt implementation. If retaining bcrypt for an existing system, account for its input limit and choose a suitable computation cost.
  • Let the library generate a unique salt and store the cost parameters with the hash. Salts make precomputation and comparisons of identical passwords harder; they do not prevent hash collisions.

Examples

Before

javascript
const crypto = require('crypto');

function setUserPassword(user, pwtext) {
  const hash = crypto.createHash('md5').update(pwtext).digest('hex');
  user.setPassword(hash);
}

After

javascript
const bcrypt = require('bcrypt');

function setUserPassword(user, pwtext) {
  const saltRounds = 12; // Example cost: tune for the service environment
  bcrypt.hash(pwtext, saltRounds, function(err, hash) {
    if (err) throw err;
    user.setPassword(hash);
  });
}

The first excerpt uses fast MD5 without a unique salt, making candidate testing inexpensive. The second lets bcrypt generate the salt and apply a cost factor, increasing the cost of guessing. The sample cost of 12 is not a universal guarantee: tune it for the service, handle bcrypt's 72-byte input limit, and send hashing failures through the application's error-handling path.

References