Unlocking Secure Password Storage with Salt Hashing
What is Hashing?
Hashing is a crucial concept in cryptography that involves mapping data of any size to a fixed-length string using an algorithm. This one-way function is primarily used for authentication purposes.
The Power of Salt Hashing
Salt hashing is a method that adds an extra layer of security to password storage. It involves combining a user-entered password with a random string of characters (salt) and then hashing the combined string using a suitable crypto hashing algorithm. The resulting hash is stored in the database, ensuring that plaintext passwords are never stored.
Getting Started
To follow along with this tutorial, you’ll need:
- A basic understanding of Node.js
- A code editor, such as VS Code, installed
- POSTMAN installed
- MongoDB set up
Crafting the Hashing Functions
We’ll create three functions to perform the following tasks:
- Generate a random salt
- Hash the data
- Compare the hashes
Setting Up the Node.js Application
Create a package.json
file to document dependencies and an index.js
file, which will serve as the root of our application.
const crypto = require('crypto');
const log = (message) => console.log(message);
Generating the Salt
Our first function will generate a random salt. This function takes in a number as a parameter to define the length of the salt. We’ll add a simple validator to ensure the number is greater than 15.
const generateSalt = (length) => {
if (length <= 15) {
throw new Error('Salt length must be greater than 15');
}
return crypto.randomBytes(length).toString('hex');
};
Hashing the Data
Next, we’ll define our hashing algorithm using the crypto.createHmac()
method. We’ll use the sha512 algorithm and pass in our salt as the key.
const hashData = (password, salt) => {
const hmac = crypto.createHmac('sha512', salt);
hmac.update(password);
return hmac.digest('hex');
};
Comparing the Hashes
Our compare password function will use the same algorithm to hash the inputted password and then test whether the new hash matches the stored hash. We’ll write some validation to check whether the password or hash is provided and whether the type of password is a string and type of hash is an object.
const compareHashes = (inputPassword, storedHash, salt) => {
if (!inputPassword ||!storedHash ||!salt) {
throw new Error('Password, hash, and salt are required');
}
if (typeof inputPassword!== 'tring' || typeof storedHash!== 'object') {
throw new Error('Invalid password or hash type');
}
const hashedInputPassword = hashData(inputPassword, salt);
return hashedInputPassword === storedHash.hash;
};
Putting it All Together
Now that we have our hashing functions, let’s create a test.js
file to test our hasher module. We’ll set up a simple express server, connect to MongoDB, and create the necessary routes.
// Import dependencies and create an express app
const express = require('express');
const app = express();
const mongoose = require('mongoose');
// Connect to MongoDB
mongoose.connect('mongodb://localhost:27017/password-hash-db', { useNewUrlParser: true, useUnifiedTopology: true });
// Define the User model
const userSchema = new mongoose.Schema({
username: String,
password: String,
salt: String,
});
const User = mongoose.model('User', userSchema);
// Register route
app.post('/register', (req, res) => {
const { username, password } = req.body;
const salt = generateSalt(16);
const hashedPassword = hashData(password, salt);
const user = new User({ username, password: hashedPassword, salt });
user.save((err) => {
if (err) {
res.status(500).send(err);
} else {
res.send(`User created successfully`);
}
});
});
// Login route
app.post('/login', (req, res) => {
const { username, password } = req.body;
User.findOne({ username }, (err, user) => {
if (err) {
res.status(500).send(err);
} else if (!user) {
res.status(404).send('User not found');
} else {
const isValid = compareHashes(password, user.password, user.salt);
if (isValid) {
res.send(`Login successful`);
} else {
res.status(401).send('Invalid password');
}
}
});
});
// Start the server
const port = 3000;
app.listen(port, () => {
console.log(`Server started on port ${port}`);
});
Testing the Password Hasher
Open POSTMAN and make a post request to /register
following the defined schema. Then, implement the login route and test it using POSTMAN. Our password hasher is working perfectly!
Note: While this guide demonstrates how salting works in Node.js crypto, it’s essential to note that this implementation has some flaws and shouldn’t be used in production. Better tools, such as Bcrypt, are more suitable for production applications. The source code is available on GitHub.