Remediation
Secure Password Storage
Remediation
The first defense against the password weaknesses covered in Lesson 3.2 is secure password storage. Passwords should never be stored in plaintext, encrypted reversibly, or processed with fast general-purpose hashing algorithms such as MD5 or SHA-1.
Instead, passwords should be processed using a slow, adaptive, salted password-hashing algorithm designed specifically to make offline cracking expensive. Modern applications should generally use Argon2id or bcrypt, with the work factor configured appropriately for the application's environment.
Conceptually:
User password
β
Slow password-hashing algorithm
β
Unique salt + computational work
β
Stored password hashWhen the user logs in, the submitted password is verified against the stored hash rather than being decrypted:
if (Hash::check($password, $user->password_hash)) {
// Authentication succeeds
}The purpose of a slow adaptive hash is to make offline password cracking expensive if an attacker obtains the application's password database. It does not make weak passwords safe; a predictable password can still eventually be cracked.
Password Strength Enforcement:
Secure storage is only one part of password defense. New passwords should also be checked against known-compromised password lists so that users cannot choose credentials that attackers are already likely to try.
The Have I Been Pwned Pwned Passwords service supports this using a k-anonymity model. The application hashes the password locally and sends only a small prefix of that hash to the service rather than sending the plaintext password itself.
The principle is:
Candidate password
β
Hash locally
β
Send only hash prefix
β
Check against breached-password corpus
β
Reject known-compromised passwordThis is generally more useful than relying exclusively on arbitrary composition requirements such as:
Must contain:
β uppercase
β lowercase
β number
β symbol
β 10 charactersA password can satisfy all of those rules while still being highly predictable. A better policy prioritizes length and resistance to known-compromised choices, while avoiding unnecessary requirements that encourage predictable password construction or reuse.
This aligns with the NIST SP 800-63B approach discussed in Lesson 3.2 password policies should focus on preventing commonly used or compromised passwords rather than treating superficial character complexity as a reliable measure of strength.