Over a million developers have joined DZone.

Node.js: Tales From the bcrypt

Having spent untold hours on Spring, PHP, and .NET-based web projects, most would agree that bcrypt is considered a best practice for storing passwords in most cases. Read on to learn more.

· Web Dev Zone

Start coding today to experience the powerful engine that drives data application’s development, brought to you in partnership with Qlik.

In its nearly seven years of existence, Node.js has brought server-side JavaScript programming to the forefront.  The language has also made rapid development of scalable, flexible, and dare I say powerful web services and applications more accessible.

For yours truly, coming from the strongly-typed camp and having worked primarily on the non-client facing side of things, I have a bit of a love-hate relationship with JavaScript: sure, it can accomplish some very cool things, but it comes at the cost of eschewing most other software engineering concepts I have come to know and love.

Image title

"What did ye say about Javascript?"

(Courtesy: hiddenremote.com)

That said, for all the JavaScript-specific issues I have had to get over (callback hell, anyone?), I have come to appreciate and even enjoy using Node.js, especially for creating RESTful APIs.

Now, core to most (if not all) REST APIs is client authentication.  Having spent untold hours on Spring, PHP, and .NET-based web projects, most would agree that bcrypt is considered a best practice for storing passwords in most cases (discussing scrypt and the like is outside of the scope of this article).

(Side note: For an excellent summary on password storage, check out OWASP's cheat sheet here.)

So, using bcrypt in my Node.js applications is a pretty safe bet.

npm install bcrypt

And, in our actual Node.js code...

var bcrypt = require('bcrypt');

// create hashed password (synchronously)
var password = bcrypt.hashSync("abc123DEF", 12); // where 12 is the work factor

// check passed-in password (sychronously)
var isMatchingPassword = bcrypt.compareSync("abc123DEF", password);

Easy as pie!  The performance is pretty good, too, considering that it's happening via JavaScript (though this bcrypt library makes use of compiled libs on the server).  Of course, this is also largely dependent on the work factor chosen.

So What? This Is All Pretty Obvious

In most cases, this would be sufficient, especially if you plan to deploy to a *nix-based environment; however, as can often be the case, developers may need to develop in a Windows environment.  Now, short of a VM or Docker-based solution, this can be a tricky proposition.

This particular bcrypt library requires external libraries such as OpenSSL, VC++ runtimes, and other Windows SDK-based libraries.  Older, 32-bit versions of Windows don't seem to have much of a problem; however, with 64-bit versions now becoming the norm, there have been several instances where running the code above in such an environment have been plagued by problems.

Oh. I See. So, What Can I Do?

For some, the solutions listed here in StackOverflow may be enough to overcome the issues and get the bcrypt library above working.  

For others, though, this may not be the case.  Speaking from experience, I managed to waste half a day going through those solutions in various permutations to no avail.  And, for a company that does not have a lot of time to waste on environment setup, I abandoned the task feeling somewhat defeated by Windows (which I am sure happens to many users regularly).

One of the alternative solutions presented in the StackOverflow link above includes switching to a different bcrypt library; one that does not rely on compiled libraries and runs purely in Javascript.  Such libraries include:

This solution works great!  But it isn't without its tradeoffs, namely...

Performance

It makes sense that the Javascript-implemented bcrypt libraries would run a bit slower.  But, just how much slower?  Is it worth the tradeoff?  Experimentation is in order!

Adrian Lynch has a good benchmarking utility for such a comparison located here.  I cloned the repository and modified it to also compare bcrypt-nodejs (the other two libraries mentioned above are already in the code).

Without going into every single run, it seems that, at a minimum, the JavaScript-based libraries are 2.5x slower than the original bcrypt library we used.

Here are some results gathered while running the benchmarks with a work factor of 12, iterating through each version 10 times, run on my Macbook Pro (Intel i5 2.6GHz, dual cores, 16GB RAM):

➜  bcrypt-vs-bcrypt git:(master) ✗ node index.js
Bcrypts ready? Fight!
bcrypt - 10 iterations took 3304ms which is an average of 330ms each
bcrypt-nodejs - 10 iterations took 8554ms which is an average of 855ms each
bcryptjs - 10 iterations took 9214ms which is an average of 921ms each
twin-bcrypt - 10 iterations took 8978ms which is an average of 897ms each

➜  bcrypt-vs-bcrypt git:(master) ✗ node index.js
Bcrypts ready? Fight!
bcrypt - 10 iterations took 3290ms which is an average of 329ms each
bcrypt-nodejs - 10 iterations took 8350ms which is an average of 835ms each
bcryptjs - 10 iterations took 8896ms which is an average of 889ms each
twin-bcrypt - 10 iterations took 8990ms which is an average of 899ms each

➜  bcrypt-vs-bcrypt git:(master) ✗ node index.js
Bcrypts ready? Fight!
bcrypt - 10 iterations took 3268ms which is an average of 326ms each
bcrypt-nodejs - 10 iterations took 8244ms which is an average of 824ms each
bcryptjs - 10 iterations took 8966ms which is an average of 896ms each
twin-bcrypt - 10 iterations took 9140ms which is an average of 914ms each

➜  bcrypt-vs-bcrypt git:(master) ✗ node index.js
Bcrypts ready? Fight!
bcrypt - 10 iterations took 3309ms which is an average of 330ms each
bcrypt-nodejs - 10 iterations took 8270ms which is an average of 827ms each
bcryptjs - 10 iterations took 8886ms which is an average of 888ms each
twin-bcrypt - 10 iterations took 9097ms which is an average of 909ms each

➜  bcrypt-vs-bcrypt git:(master) ✗ node index.js
Bcrypts ready? Fight!
bcrypt - 10 iterations took 3321ms which is an average of 332ms each
bcrypt-nodejs - 10 iterations took 8306ms which is an average of 830ms each
bcryptjs - 10 iterations took 9000ms which is an average of 900ms each
twin-bcrypt - 10 iterations took 8973ms which is an average of 897ms each

So, roughly 3 passwords/second can be handled in this comparison at best by the original bcrypt library, with just over 1 password/second being handled by the other libraries.  Depending on your throughput requirements and the processor on which you will be running the code, you may have to do some tweaking with the work factor.  The degree of security required in your project coupled with your destination server's CPU may mean that the tradeoff of speed is not acceptable.

Conclusion

The bottom line is to be prepared ahead of time and do the benchmarking tests to determine which bcrypt library is going to work best for you in your Node.js application.  Usually, however, unless you have a team that includes Windows developers who absolutely must use a native Windows environment, the original, compiled bcrypt library will always be your best.

If it comes down to choosing which Javascript-implemented (that is, non-compiled) bcrypt library to use, bcrypt-nodejs ekes out a victory, although the differences become more pronounced with higher work factors.

Create data driven applications in Qlik’s free and easy to use coding environment, brought to you in partnership with Qlik.

Topics:
node.js ,security ,performance ,development

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}