How to Hash Passwords Using Node.js Crypto Module
This article explains the purpose of the built-in crypto
module in Node.js and demonstrates how to use it for secure password
hashing. You will learn the importance of cryptographic functions in
application security, how to securely hash a password using a salt, and
how to verify user credentials during authentication.
Purpose of the Node.js Crypto Module
The crypto module is a built-in Node.js library that
provides cryptographic functionality, wrapping OpenSSL’s cryptographic
functions. It allows developers to secure application data without
relying on third-party libraries. The module provides tools for:
- Creating secure hashes (SHA-256, MD5, etc.)
- Generating cryptographically strong pseudo-random data (like salts or tokens)
- Symmetric and asymmetric encryption and decryption
- Creating and verifying digital signatures
For password storage, the crypto module is primarily
used to perform one-way hashing. One-way hashing ensures that even if a
database is compromised, the actual plain-text passwords of users remain
unreadable.
Why Hashing Passwords Requires a Salt
Simply hashing a password is not secure enough. Attackers can use precomputed tables of hashes (known as rainbow tables) to easily crack simple hashed passwords.
To prevent this, you must use a salt. A salt is a unique, random string generated for each user that is combined with the password before hashing. This ensures that two users with the exact same password will have entirely different hashes in the database.
How to Hash a
Password using crypto.scrypt
Node.js offers the scrypt algorithm within the
crypto module, which is specifically designed to be slow
and resource-intensive to prevent brute-force attacks.
Here is how to generate a secure salt and hash a password:
const crypto = require('crypto');
function hashPassword(password) {
// Generate a random 16-byte salt
const salt = crypto.randomBytes(16).toString('hex');
// Hash the password using scrypt with the generated salt
const derivedKey = crypto.scryptSync(password, salt, 64);
// Combine the salt and hash to store in the database
const hashedPassword = `${salt}:${derivedKey.toString('hex')}`;
return hashedPassword;
}
const secureStorage = hashPassword("mySuperSecretPassword123");
console.log("Stored Value:", secureStorage);In this example, the resulting string contains both the salt and the generated hash, separated by a colon. You should store this combined string in your database.
How to Verify a Password During Login
To verify a user’s password during login, you must retrieve the stored salt and hash from the database, hash the incoming password attempt using that same salt, and compare the results.
Here is how to verify the password:
function verifyPassword(passwordAttempt, storedValue) {
// Split the salt and the hash from the stored database string
const [salt, originalHash] = storedValue.split(':');
// Hash the login attempt using the same salt
const hashToVerify = crypto.scryptSync(passwordAttempt, salt, 64).toString('hex');
// Compare the original hash with the new hash
return hashToVerify === originalHash;
}
// Example usage
const isMatch = verifyPassword("mySuperSecretPassword123", secureStorage);
console.log("Password match status:", isMatch); // Outputs: trueBy utilizing crypto.scryptSync alongside random salts,
you can easily implement robust, secure password hashing in your Node.js
applications without external dependencies.