Authentication – from “Programming JavaScript Applications”

JavaScript | Node | Web Architecture 7 7 Comments

I have read a lot of books about how to build applications, but I’ve never seen one that adequately covers the topic of authentication, so I decided to dedicate a section to it in my book, Programming JavaScript Applications. Enjoy this free excerpt.

Authentication

Authentication is the mechanism which confirms the identity of users trying to access a system. In order for a user to be granted access to a resource, they must first prove that they are who they claim to be. Generally this is handled by passing a key with each request (often called an access token). The server verifies that the access token is genuine, that the user does indeed have the required privileges to access the requested resource, and only then is the requset granted.

There are many ways to grant a user an access token. The most common is a password challenge.

Passwords

Passwords should be stored with a one way encryption hash, so that even if a malicious intruder obtains access to the user database, they still won’t have access to user passwords.

The hash should be sufficiently long not just to prevent an attack from a single machine, but to prevent an attack from a large cluster of machines.

Worms targeting vulnerable versions of popular website platforms such as WordPress and Drupal have become common. Once such a worm takes control of a website and installs its payload, it can recruit all of the site’s traffic into a JavaScript botnet, and, among other things, use visitor CPU power to crack stolen password databases which fail to implement the security precautions outlined here.

There are botnets that exist today with over 90,000 nodes. Such botnets could crack MD5 password hashes at a rate of nine billion per second.

Passwords are vulnerable to the following common attacks:

  • Rainbow tables
  • Brute force
  • Variable time equality
  • Passwords stolen from third parties

Rainbow tables

Rainbow tables are precomputed tables used to look up passwords using stolen hashes. Once bad guys get their hands on user passwords, they’ll attempt to attack popular services such as email and bank accounts — which spells very bad PR for your service.

There are rainbow tables that exist today which can discover almost every possible password up to 14 characters. To prevent password theft by rainbow table, users should choose passwords of at least 14 characters. Sadly, such passwords are definitely not convenient, particularly on mobile devices. In other words, you should not rely on users to select appropriate passwords.

Rainbow tables can significantly reduce the time it takes to find a password, at the cost of memory, but with terabyte hard drives and gigabytes of RAM, it’s a trade off that is easily made. That said, it is possible to protect your service against rainbow table attacks.

Password Salts

One defence you can employ against rainbow tables is password salting. A salt is a sequence of random characters that gets paired with a password during the hashing process. Salts should be cryptographically secure random values of a length equal to the hash size. Salts are not secrets, and can be safely stored in plaintext alongside the user’s other credentials.

Salting can protect passwords in a couple of ways:

First, a uniquely generated salt can protect your password databases against existing rainbow tables. Using a random salt makes your site immune from these attacks. However, if you use the same salt for every password, a new rainbow table can be generated to attack the password database.

Second, if two different users use the same password, the compromised password will grant access to both user accounts. To prevent that, you must use a unique salt for each password. Doing so makes a rainbow table attack impractical.

Node.js supplies a suitable random generator called crypto.randomBytes(). It returns a buffer, so you’ll need to wrap it to get a suitable salt string:

The operation is asynchronous because the cryptographically secure random number generator takes time to collect enough entropy to complete the operation.

Brute force

Rainbow tables get all the blogger attention, but Moore’s Law is alive and well, and brute force has become a very real threat. Attackers are employing GPUs, super computing clusters that cost less than $2,000, and JavaScript botnets comprised of tens of thousands of browsers visiting infected websites.

A brute force attack will attempt to crack a password by attempting a match using every possible character combination. A simple single-iteration hash can be tested at the rate of millions of hashes per second on modern systems.

One way to thwart brute force attacks is to programatically lock a user’s account after a handful of failed login attempts. However, that strategy won’t protect passwords if an attacker gains access to the password database.

Key stretching can make brute force attacks impractical by increasing the time it takes to hash the password. This can be done by applying the hash function in a loop. The delay will be relatively unnoticed by a user trying to sign in, but will significantly hamper an attacker attempting to discover a password through brute force.

You should not simply pick a random hash function and apply it in a loop. It’s too easy to unwittingly open up attack vectors. Instead, use an established standard for iterative hashing, such as bcrypt or PBKDF2.

I discovered 100 hashes in less than 1ms using a simple MD5 algorithm, and then tried the same thing with Node’s built-in crypto.pbkdf2() function (HMAC-SHA1) set to 80,000 iterations. PBKDF2 took 15.48 seconds. To a user performing a single login attempt per response, the slow down is barely noticed, but it slows brute force to a crawl.

Usage is deceptively simple:

However, there are important considerations that shouldn’t be overlooked, such as generating the appropriate unique, crytographically secure random salt of the right length, and calculating the number of iterations in order to balance user experience and security.

Variable time equality

If it takes your service longer to say no to a slightly wrong password than a mostly wrong password, attackers can use that data to guess the password, similar to how you guess a word playing hangman. You might think that random time delays and network timing jitter would sufficiently mask those timing differences, but it turns out an attacker just needs to take more timing samples to filter out the noise and obtain statistically relevant timing data:

From Crosby et al. “Opportunities And Limits Of Remote Timing Attacks”:

We have shown that, even though the Internet induces significant timing jitter, we can reliably distinguish remote timing differences as low as 20µs. A LAN environment has lower timing jitter, allowing us to reliably distinguish remote timing differences as small as 100ns (possibly even smaller). These precise timing differences can be distinguished with only hundreds or possibly thousands of measurements.

The best way to beat these attacks is to use a constant time hash equality check, rather than an optimized check. That is easily achieved by iterating through the full hash before returning the answer, regardless of how soon the answer is known.

For more information, see Coda Hale’s “A Lesson in Timing Attacks”.

Here is an example of a constant time string equality algorithm in JavaScript:

Stolen passwords

By far the biggest threat to password security is the fact that these tactics have already worked against other websites, and users have a tendency to reuse passwords across different sites. Since you don’t have access to the user’s other accounts for verification, there’s little you can do to enforce unique passwords on your website.

As you have seen, passwords alone are an ineffective authentication system, but they can still be useful in combination with other authentication factors.

Credential

I searched for a suitable open source password authentication module in NPM, but I couldn’t find one that met all of the criteria you should consider when you’re implementing password authentication in your applications. This is a critical component of your system security, so it’s important to get it right. I created a library to make it easy.

Install credential:

.hash():

.verify():

Multi-factor authentication

Because of the threat of stolen passwords, any policy which relies solely on password protection is unsafe. In order to protect your system from intruders, another line of defense is necessary.

Multi-factor authentication is an authentication strategy which requires the user to present authentication proof from two or more authentication factors: The knowledge factor (something the user knows: password, etc…), the possession factor (something the user has: mobile phone, etc…), and the inherence factor (something the user is, fingerprint, etc…).

Knowledge factor

A common secondary security mechanism that was widely implemented in the financial industry just a few years ago are “security questions”. Pairing a password with security questions does not qualify as multi-factor authentication, though, because you need the user to pass challenges from two or more authentication factors. Using multiple knowledge factor challenges does not prevent a determined snoop from breaking in.

Multi-factor authentication means that an attacker would have to be both a snoop and a thief, for instance.

Posession factor

For corporate and government intranets, it’s common to require some type of physical token or key to grant access to systems. Mechanisms include USB dongles, flash card keys, etc…

OTPs (One Time Passwords) are short-lived passwords that work only for a single use. They satisfy the posession factor because they’re usually generated by a dedicated piece of hardware, or by an app on the user’s mobile phone. The device is paired with the service that is being authenticated against in a way that cannot be easily spoofed by impostors.

Google released a product called Google Authenticator that generates one time passwords for mobile devices. There is a node module called speakeasy that lets you take advantage of Google authenticator to authenticate users using the posession factor.

Install Speakeasy:

Then take it for a spin:


  1. Very cool section. I was hoping it would cover oAuth and login with Facebook, etc.

    • Eric Elliott - August 5, 2013

      Hi Bryan,

      Those topics are covered in the same chapter in a section called “Authorization”. Authentication is the process of verifying if the user or the app is who or what they claim to be. Authorization is the process of determining whether or not the user or app has permission to do what they’re trying to do. OAuth2 and company are standards that enable a user to authorize an app to act on the user’s behalf, or access a user’s data. More on that soon!

    • Michael Bennett - October 1, 2013

      Bryan,

      If you’re interested in oauth login demos, there’s a series of node packages branded “passport” that will handle authorization. There are a number of different strategies (facebook/google/twitter/windowsLive/linkedIn….) that all have examples on git hub. http://passportjs.org/guide/

      AFAIK you’ll still need something like Eric’s credential to actually deal with hashing the password, and you’ll also need to store it somewhere. Unless of course you rely on the third party to do all your authentication, then you just need to worry about authorization. Even still you need some sort of unique identifier for the user’s third party account, so you can recognize them on future visits.

      • Eric Elliott - October 2, 2013

        Thanks for your comment, Michael. I have written about Passport before (it’s actually mentioned in this chapter of my book). I like that it’s modular, and you only need to install the strategies you actually use.

  2. Michael Bennett - August 20, 2013

    Thanks for the bit about variable time equality, not a lot of people take the time to point that out.

  3. If my understanding of hash/salt is correct, wouldn’t storing the hash and salt together make it easy to crack a individual password upon gaining access to the database?
    I think it needs to be clarified that this strategy is good at combatting cracking MANY passwords, but not the best for ONE password.

    • Eric Elliott - September 10, 2013

      Hi stongo,

      No, the salt is not a secret, and there’s no need to hide it. The way that cracking a password works using the brute force method is you try a password. If it’s wrong, you try another password, and so on. The idea is to try every possible combination of characters until you get it right. Knowing the salt doesn’t help a brute-force attacker, since the salt is irrelevant to this strategy.

      The point of a salt is to make the same passwords result in a different hash. Without a salt, a common password is going to show up with the same hash, which means if you crack a password that’s used by five other users, instead of just gaining access to one account, you gain access to six. With the salt, it shows up in the database with a different hash.

Add Comment Register



Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">