Storing passwords: hashing, salting and BCrypt
Never store passwords, or anything that can be turned back into them. Store a hash made with a slow, salted password-hashing algorithm:
- Hash: a one-way function. You can check a password against it, but not reverse it.
- Salt: random data added to each password before hashing, so the same password gives different hashes and precomputed tables are useless. BCrypt generates it and stores it inside the hash.
- Slow on purpose: a cost factor makes each hash take tens or hundreds of milliseconds. Unnoticeable at login, crippling for an attacker trying billions of guesses.
Use BCrypt (Spring's default), Argon2 or PBKDF2. Never MD5, SHA-1 or plain SHA-256: they're designed to be fast.
In Spring, DelegatingPasswordEncoder prefixes each hash with its algorithm ({bcrypt}), so you can switch algorithms later and upgrade old hashes when users next log in. For password rules, length beats complexity: require 12 or more characters and reject passwords known from data breaches.
Example
@Service
class RegistrationService {
private final PasswordEncoder encoder;
private final UserRepository users;
RegistrationService(PasswordEncoder encoder, UserRepository users) { this.encoder = encoder; this.users = users; }
public void register(String email, String rawPassword) {
if (rawPassword.length() < 12) throw new IllegalArgumentException("Use at least 12 characters");
users.save(new AppUser(email, encoder.encode(rawPassword))); // only the hash is stored
}
}
PasswordEncoder bcrypt = new BCryptPasswordEncoder(12); // cost 12: 2^12 rounds
String hash = bcrypt.encode("correct horse battery staple"); // $2a$12$<salt><hash>, different every time
bcrypt.matches("correct horse battery staple", hash); // true
bcrypt.matches("correct horse battery stapel", hash); // falseCommon mistake
Hashing passwords with SHA-256 or MD5 "because it's a hash". They're fast by design: a GPU tries billions of guesses per second against them.
Under the hood
Tune the cost so one hash takes a noticeable fraction of a second on your production hardware, and revisit it as hardware gets faster. BCrypt only uses the first 72 bytes of a password; Argon2 has no such limit and resists GPU attacks better, which is why it's often recommended for new systems. Implement UserDetailsPasswordService and Spring will re-hash passwords with the current encoder automatically on successful login.
Check yourself
You hash the same password twice with BCrypt. The two hashes are…
How this connects
Where this leads
You've reached the end of this thread. Try a learning path for what's next.
Was this lesson helpful?
Finished reading? Mark it complete to track your progress.