How to store passwords in the database
By Flavio Copes
Never store raw passwords in your database, store a hash instead. Learn how to hash and verify passwords in Node.js with bcrypt using hash() and compare().
You don’t. You don’t store passwords in the database. You store the password hash, a string generated from the password, but from which no one can go back to the original password value.
Why you store a hash
Databases get leaked. It happens to small apps and to huge companies.
If you store plain passwords, whoever gets a copy of your database owns every account. And since people reuse passwords everywhere, they can try those same credentials on other sites too.
If you store hashes instead, the attacker only gets strings that can’t be reversed back to the passwords.
The password itself still needs to be strong before you hash it — I built a free password generator that creates random passwords and passphrases with entropy estimates.
Why bcrypt?
You might wonder: why not hash with SHA-256, which is built into Node?
Because SHA-256 is designed to be fast. Fast is great for checksums, and terrible for passwords: an attacker with a GPU can try billions of guesses per second against a fast hash.
bcrypt is deliberately slow, and you decide how slow. It also generates a random salt for each hash, so two users with the same password get two different hashes.
Using Node, install bcrypt:
npm install bcrypt
Require it, and define the salt rounds value, we’ll use it later:
const bcrypt = require('bcrypt')
const saltRounds = 10
saltRounds is the cost factor. Each increment doubles the time needed to compute a hash. 10 is a good default.
Create a password hash
Create a password hash using:
const hash = await bcrypt.hash('PASSWORD', saltRounds)
where PASSWORD is the actual password string.
If you prefer callbacks:
bcrypt.hash('PASSWORD', saltRounds, (err, hash) => {
})
The result is a 60-character string that looks like this:
$2b$10$Ro0CUfOqk6cXEKf3dyaM7OhSCvnwM9s4wIX9JeLapehKK5YdLxKcm
It embeds the algorithm version, the cost factor, and the salt, so you don’t need a separate salt column.
Then you can store the hash value in the database.
Verify the password hash
To verify the password, compare it with the hash stored in the database using bcrypt.compare():
const result = await bcrypt.compare('PASSWORD', hash)
//result is true or false
Using callbacks:
bcrypt.compare('somePassword', hash, (err, result) => {
//result is true or false
})
compare() reads the salt from the stored hash, hashes the login attempt with it, and checks if the two match.
Don’t try to verify by calling bcrypt.hash() again and comparing the strings yourself. hash() generates a new random salt every time, so the result will never match the stored one.
One more thing to check: make sure the database column holds at least 60 characters. A shorter column can truncate the hash (or reject it, depending on the database), and every login fails from then on.
Related posts about database: