Harsh Patel 🕸 Web aficionado 💻 Writer + Programmer 🎯 Dreams ➡️ Vision ➡️ Reality

Password hashing in Node.js with bcrypt

5 min read 1441

Password Hashing in Node.js With Bcrypt

The utmost responsibility of any system designer is to protect user data. Data breaches can cause damage worth millions, and according to Imperva, the US has the highest data breach cost.

The chances of misusing data are higher when data is just plain text. If you fail to protect data, the next step is to make it unreadable by encrypting it so the attacker won’t get much out of it. For example, suppose somebody gained access to the email and password to your social media profile. In that case, it’s straightforward to access your profile without your knowledge. However, what happens if your password is encrypted? Your account is safe even after the attack.

If you want to protect users’ emails, that’s great, but protecting user passwords is a must. Although a user must set a strong password, the user and the system both work on password protection. Luckily, many methods exist to perform encryption/decryption to help increase password safety. This article will show you how to use password hashing with the bcrypt library in Node.js.

Jump ahead:

What is password hashing?

Password hashing is the process of turning a password into alphanumeric letters using specific algorithms. Hashing is beneficial when bad guys breach the data. With hashing, the data they get is in hash format, and hashed data is unintelligible. Some popular algorithms for password hashing include bcrypt and SHA. In this article, we’ll focus on using bycrypt to hash passwords in Node.js. Here’s an example of hashing plain text:

hash('[email protected]') = 1b21hb2hb1u2gu3g2fxy1v2ux1v2y3vu12g4u3ggvgu43598sa89da98sd79adshuavusdva9sdguasd

Password hashing in Node.js with bcrypt

Bcrypt is a library to help you hash passwords. It uses a password-hashing function that is based on the Blowfish cipher. The Blowfish cipher is a symmetric block cipher that provides the best encryption rate in the industry; thus, it can be used in cipher suites and encryption products.

Bcrypt uses salt to protect against attacks like rainbow table, brute force, and more. Bcrypt is an adaptive function, so if you call bcrypt’s function frequently, it becomes slower. This hinders an attacker’s ability to benefit from a brute-force attack.

Bcrypt dependencies

Bcrypt needs some dependencies to function correctly. Bcrypt requires the node-gyp package, which compiles native add-on modules for Node.js. Bcrypt is also dependent on Python, and you’ll need ≥v2.x. Windows users need C# and C++ options installed with their VS instance. You will also need OpenSSL v0.7.7.

Examples of password hashing with bcrypt in Node.js

It is important to salt and hash users’ passwords before storing them for data safety intents. Bcrypt turns a simple password into fixed-length characters called a hash. Before hashing a password, bcrypt applies a salt,  a unique random string that makes the hash unpredictable.

Let’s create a Node.js project and use bcrypt to hash passwords. After making a server file, you need to install bcrypt:

$ mkdir bcrypt_demo
$ cd mkdir
$ npm init -y
$ touch app.js
$ npm install bcrypt --save

Now, you are ready to work with bcrypt. Let’s import it and define saltRounds, as a cost or work factor:

const bcrypt = require("bcrypt")
const saltRounds = 10
const password = "[email protected]"

Password encryption in Node.js using the JavaScript async promise

The JavaScript Promise is an object returned by async function, which is a representation of the current state. When the Promise is returned to the caller, it provides methods to handle the success or failure of the operation based on the condition.

There are two methods for password encryption. Here’s the first method:

bcrypt
  .genSalt(saltRounds)
  .then(salt => {
    console.log('Salt: ', salt)
    return bcrypt.hash(password, salt)
  })
  .then(hash => {
    console.log('Hash: ', hash)
  })
  .catch(err => console.error(err.message))

First, we will create a salt using bcrypt’s genSalt function. Here, genSalt will take one argument as a saltRound number. Then, if it succeeds, we will provide the result to hash along with our password.

As a successful result, we will get the hash. In this method, we used JavaScript’s async promise.

You can see the output as shown below once you fire Node app.js:

Salt: $2b$10$t7oxiwchWGHa/B9w0AzrYO
Hash: $2b$10$t7oxiwchWGHa/B9w0AzrYO2WH2rQbA86YSuQjSTmwIrpC/0ZXN7V2

This hash will be stored in the database along with other details. One more thing, do you think I will get the result if I re-run the code? Will it generate the same output each time?

Using the bcrypt.compare function to hash passwords in Node.js

Obviously, not! The bcrypt.hash will generate a unique hash based on special salt every time. That’s how it prevents rainbow table attacks. Now, let’s look at the second method:

bcrypt
  .hash(password, saltRounds)
  .then(hash => {
    console.log('Hash ', hash)
  })
  .catch(err => console.error(err.message))

Here, we will call only has function and provide the saltRound only. This will also generate a unique hash each time. Now, how will we validate that hash? This will be necessary to perform user logins.

So, for that bcrypt, we have a bcrypt.compare function that will take care of that part:

bcrypt
  .hash(password, saltRounds)
  .then(hash => {
          userHash = hash 
    console.log('Hash ', hash)
    validateUser(hash)
  })
  .catch(err => console.error(err.message))

function validateUser(hash) {
    bcrypt
      .compare(password, hash)
      .then(res => {
        console.log(res) // return true
      })
      .catch(err => console.error(err.message))        
}

If the res is true, the password-generated hash for it is matched.

Node.js bcrypt password hashing information

As you see at the end, you’ll get a hash that is 60 characters long:

$[algorithm]$[cost]$[salt][hash]
// $2b$10$b63K/D03WFBktWy552L5XuibmiD5SxCrKg9kHCqOYaZwxRjIg14u2

The bifurcation of hash is like this:

  • Algorithm: Will be "$2a$" or "$2b$" which means BCrypt
  • Cost: Represents the exponent used to determine how many iterations 2^n
  • Salt: (16-byte (128-bit)), base64 encoded to 22 characters
  • Hash: (24-byte (192-bit)), base64 encoded to 31 characters

Password hashing data costs

Hashing data will go through a series of saltRounds, resulting in a secure hash that is unpredictable to any system or user. A module will then use a given value and perform 2^r. Hashing options data costs generally refer to the time one hash round takes, which depends on the system’s hardware.

On a 2GHz core processor, you can roughly expect the following:

rounds=8 : ~40 hashes/sec
rounds=9 : ~20 hashes/sec
rounds=10: ~10 hashes/sec
rounds=11: ~5  hashes/sec
rounds=12: 2-3 hashes/sec
rounds=13: ~1 sec/hash
rounds=14: ~1.5 sec/hash
rounds=15: ~3 sec/hash
rounds=25: ~1 hour/hash
rounds=31: 2-3 days/hash

Benefits of password hashing in Node.js with bcrypt

Bcrypt has significant advantages over other hashing methods like MD5, SHA1, SHA2, and SHA3. They can all perform hashing of a large number of data in less time. Suppose an attacker has a robust system capable of trying 700-900 million passwords in seconds. Your password containing alphanumeric and special character values will be cracked in a few seconds.



So, now you know that all of these hashing methods cannot be used to encrypt the password. Now the main question is, how does bcrypt provide a significant advantage here? Bcrypt was built upon Blowfish keying schedule and used a work factor, which decides how expensive the hash function will be. After knowing it, bcrypt will get slower if an attacker makes multiple requests in a single time frame. So generally, cracking one password will take 12 damn years.

Also, bcrypt uses salt, which helps prevent attacks like rainbow table attacks and is suitable for securing passwords.

Conclusion

As you know, it is crucial to secure data to avoid significant damage. An attacker may find a way to access your data storage, but well-encrypted passwords are a waste of time and effort for an attacker. They won’t get any benefits from our encrypted data.

Node.js allows us to use bcrypt without any hurdles. There is no reason to avoid it when dealing with users’ passwords and other sensitive data. A secure hashing function such as bcrypt should be necessary to make a robust system. I suggest you use it to store passwords. You won’t have to deal with problems exposing users’ sensitive information if you have done hashing using bcrypt.

200’s only Monitor failed and slow network requests in production

Deploying a Node-based web app or website is the easy part. Making sure your Node instance continues to serve resources to your app is where things get tougher. If you’re interested in ensuring requests to the backend or third party services are successful, try LogRocket. https://logrocket.com/signup/

LogRocket is like a DVR for web and mobile apps, recording literally everything that happens while a user interacts with your app. Instead of guessing why problems happen, you can aggregate and report on problematic network requests to quickly understand the root cause.

LogRocket instruments your app to record baseline performance timings such as page load time, time to first byte, slow network requests, and also logs Redux, NgRx, and Vuex actions/state. .
Harsh Patel 🕸 Web aficionado 💻 Writer + Programmer 🎯 Dreams ➡️ Vision ➡️ Reality

Leave a Reply