Blog | G5 Cyber Security

Password Leak Response: Client-Side Hashing

TL;DR

Client-side hashing can improve security after a password leak if implemented correctly, but it’s not a silver bullet. It adds complexity and relies on users re-hashing their passwords with new salts. It’s best used as part of a broader response plan including forced resets and monitoring.

1. Understanding the Problem

When a password database is leaked, attackers have access to hashed passwords. If the hashing algorithm is weak or uses common salts, these can be cracked relatively easily. Even strong hashes are vulnerable over time with increasing computing power. Client-side hashing aims to mitigate this by adding another layer of protection after the leak.

2. How Client-Side Hashing Works

Normally, passwords are hashed on the server before being stored. Client-side hashing involves hashing the password in the user’s browser *before* it’s sent to the server. This means even if the server is compromised, attackers only get hashes generated with a salt known by each individual user.

3. Steps for Implementing Client-Side Hashing After a Leak

  1. Generate New Salts: Each affected user needs a new, unique salt. This is the most critical step. Do not reuse old salts!
  2. Update Client-Side Code: Modify your website’s JavaScript to incorporate a hashing function (e.g., SHA256) and use the newly generated salt for each user. Libraries like bcrypt.js or scrypt.js can be used, but ensure they are properly vetted for security vulnerabilities.
  3. Prompt Users to Re-Hash: Users must re-submit their passwords (or a password confirmation). This is because the server only has the old hashes. The client-side code will hash the new input with the user’s unique salt before sending it to the server.
  4. Store New Hashes: Replace the compromised hashes on the server with the newly generated hashes from the client.
  5. Invalidate Old Hashes (Optional): If possible, mark the old hashes as invalid in your database. This prevents accidental use of the leaked data if it falls into the wrong hands again.

4. Example JavaScript Code Snippet

async function hashPassword(password, salt) {
  const encoder = new TextEncoder();
  const encodedPassword = encoder.encode(password);
  const hashed = await crypto.subtle.digest('SHA-256', encodedPassword);
  const hexArray = Array.from(new Uint8Array(hashed)).map(b => b.toString(16).padStart(2, '0')).join('');
  return salt + hexArray;
}

Important: This is a simplified example. Real-world implementations require careful handling of salts and secure key management.

5. Considerations & Limitations

6. Best Practices

Exit mobile version