Understanding bcrypt in MERN stack

img

Since you are reading this article, it means that you are building or have built an app that has users.

Users when they get registered, they provice a password in your database. For security reasons - in case that the database gets hacked - passwords are not stored as plain text in the database .

For this reason, in the backend we need a mechanism to transform the password into something that doesn't even look like a key anymore.

At this point I need to make a very short introduction to cryptography. After all, who doesn't love a good tale of ancient times?

First cryptography

Now, before we even had treehouses, or computers, or even electricity, there were still secrets to keep. Imagine it's ancient Rome, the era of Julius Caesar. Caesar had a knack for sending secret messages to his generals. Instead of just writing in plain Latin, he used a simple but smart trick, swapping each letter in his message with the letter three places down the alphabet. 'A' would become 'D', 'B' would become 'E', and so on. This is known as a Caesar Cipher, one of the earliest forms of cryptography.

Now, what's this "cryptography" you ask? Well, think of it like a secret language or code. It's all about taking a clear, readable message (we call this 'plaintext') and transforming it into something that looks like gobbledygook to anyone who doesn't know the code (that's 'ciphertext').

Fast forward a couple of millennia, and we've gone from swapping letters around to using super sophisticated techniques like bcrypt. But it's all rooted in the same idea that Julius Caesar had all those years ago: keeping our secrets safe from prying eyes. Now, instead of secret military orders, we're protecting data like usernames, passwords, and personal information.

Back to the main thread now, in our case we need to use something called bcrypt.


How bcrypt works

In order to understand how bcrypt works, you need to know what is salt and what is hash.

Salt

img

Salt: A random string that we will be generating of a certain length. It looks something like this: $2b$10$QODZX7f2hPvZv3yq8Qe.Ve

We will be adding such a thing to a password so when two users have the same password cannot be identified. For example if a user sets password 123 then by adding a random string to it will become $2b$10$QODZX7f2hPvZv3yq8Qe.Ve123

and when another user sets the same password 123 adding another randomly generated salt e.g. $2b$10$Ix4sYf2jBr3dG7hh9iB8dO then adding the salt to the pass becomes $2b$10$Ix4sYf2jBr3dG7hh9iB8dO123

Bcrypt automatically takes care of salt generation for us, ensuring that every password has a unique salt. This way, even if two users have the same password, their hashes will be different.

which is better that just having stored 123 in the database. But in order to increase security even more and make it much more difficult for hackers to reverse engineer and find the stored passwords we will use another technique that is being used in cryptography called hashing. But what is a hash.

Add salt and hash together and we get:

Hash

Let's meet the other half of our dynamic duo: Hash. Now, you might be thinking about hash browns, but alas, in cryptography, it's a different kind of hash (though just as tasty for our purposes)!

Think of hashing like a magical dance move. You take your secret handshake (password), add the unique add-on (salt), and then perform this dance move. The result? A crazy, complex dance sequence that looks nothing like the original handshake!

In technical terms, a hash is a function that takes an input (password + salt) and returns a fixed-size string of bytes, typically a digest that is unique to each unique input. It changes the password into a format that can't be understood if seen, kind of like a magical disguise!

It's important to remember that this dance move can't be reversed. You can't take a glance at the finished dance and figure out the original secret handshake. This one-way trip is what makes hashing such a crucial part of bcrypt, and of security in general.

Combining the salt and hash dance, we create our amazing hero: bcrypt and this is the best metaphor I know how to explain what bcrypt is:

The password that is received from the client is like a potato. Bcrypt is creating a salt, then it uses this salt to hash the password, creating a unique 'taste'. This 'taste', the hashed password, is what gets stored in the database.

When the user logs in, he is sending us his potato. In the taste we have stored in the database, we can know which is the salt, so we take the salt and we add it to the given potato. If the taste is like the one stored in the database then that means that the potato is the same as the intitial one.

Amazing! Unbelievable!

img

Let's get our hands dirty now:

Step 1: Invite Bcrypt into your Treehouse

Before we start using bcrypt, we need to add it to our project. This is as easy as inviting a new friend over! In your terminal, type:

npm install bcrypt

Step 2: Teaching Bcrypt our Secret Handshake

Now that bcrypt is part of our project, let's teach it how to handle our secret handshakes. Here's an example of how you can do it:

const bcrypt = require('bcrypt');
const saltRounds = 10; // Determining how complicated our dance should be. Don't overdo it. Max diificulty can be 32.

// Take a password
const password = 'Our Secret Handshake';

// Generate a salt
const salt = bcrypt.genSaltSync(saltRounds);

// Hash the password with the salt
const hashedHandshake = bcrypt.hashSync(password, salt);

console.log(hashedHandshake); // This will log our hashed handshake to the console!

And just like that, we can confirm whether the passwordAttempt matches the original password, all without ever knowing what the original password was. Magic, right?

Hashing Complexity: Salt Rounds

Now, you may be wondering what the 'saltRounds' variable we used in the example is all about. In simple terms, the number of salt rounds is the amount of time the data is processed for hashing. The higher the number, the longer it takes to generate the hash, and therefore the more secure the hash is.

However, keep in mind that a higher number also means more processing time, which can slow down your application, especially if you have many users logging in at the same time. So it's important to strike a balance between security and performance. A salt round of 10 is usually considered a good starting point.

And there you have it, my fellow coders. We've taken a journey from the times of Julius Caesar to the land of MERN stack, understanding the magic of cryptography and bcrypt along the way. Remember, when it comes to user data, it's better to be safe than sorry, and bcrypt is an excellent tool to help us do just that.

Remember to balance between the need for security (higher salt rounds) and the need for performance (lower salt rounds). As with many things in life, and especially in the world of coding, understanding bcrypt isn't just about mastering a new skill, it's about discovering and walking the right path to secure and reliable applications. And as we often say around here, "This is the right way to learn."

Till next time, happy coding!