Developing a Password Strength Plugin with jQuery

Tweet

Passwords are the most commonly used authentication mechanism. Even as many sites move to multi-step authentication, passwords still pay a key role in securing your account. A strong password is critical to account security, and this article will teach you how to develop a plugin that guages password strength. We are going to use the zxcvbn library and jQuery to build a fully featured password strength meter for websites.

Introduction

Generally, most uses are non-technical, and have limited knowledge about how authentication works. Even for the technical users, it’s difficult to figure out which passwords are strong and which are easily breakable. For example, a simple increase in password length does not necessarily make it harder to break.

A password strength meter calculates the strength of a user entered password. Generally, its displayed as strength levels like very weak, weak, good, strong, etc. The meter is updated on each user input, so the calculation should occur as a onkeypress or onkeyup event handler. When a user attempts to create a new account, weak passwords can be detected and rejected, improving overall site security.

Password Strength Calculation

There should be clearly defined criteria for calculating password strength. Most developers tend to use manual validation criteria for password strength meters. This is a good guideline for strengthening passwords, but it might not be the most accurate technique as it doesn’t consider the amount of time required to break the password. Instead, most manual validation depends on conditions such as:

  • Number of characters.
  • Use of capital letters, numbers, and symbols.
  • Blacklisted words.

This is not a realistic estimation of password strength as some passwords generated through these validation will be fairly easy to break. So we need an accurate measuring system for defining password strength.

zxcvbn

In this tutorial, we are planning to implement a password strength meter using zxcvbn. zxcvbn is considered to be a realistic password strength meter that utilizes a data set of common English words, repetitive patterns, sequences, and common English names to calculate strength. It also allows us to blacklist some words when calculating strength. The result provided by this function is much more accurate than manual strength calculation rules. Understanding how zxcvbn uses mathematical functions to calculate strength is beyond the scope of this tutorial. Those who want to understand the logic within zxcvbn can look at the article by Dropbox Tech Blog.

Consider the following code, which uses the zxcvbn function. The first argument is required holds the password being evaluated. In this case, the password is “password.” The second argument is optional and can contain an array of values for blacklisting. Generally, we don’t want the password to be similar to the username. So we have to at least use the username as a blacklisted value to get strong passwords.

<script type="text/javascript" >
  var blackList = ["admin"];
  var strength  =  zxcvbn("password", blackList);
</script>

The zxcvbn function returns an object containing the following properties.

  • strength.entropy – Measured in bits.
  • strength.crack_time – This is the estimated crack time.
  • strength.crack_time_display – This is also used to provide the crack time in a user friendly manner using months, years, centuries, etc.
  • strength.score – This is the actual strength that we will be using inside the password strength meter. It ranges from zero to four, where zero represents a weak password, and four represents a strong password. No matter how complex your password is, it wont go beyond four.
  • strength.match_sequence – This provides a list of patterns used to calculate the strength. This is an object with multiple objects containing patterns like brute force, dictionary, etc. You can check this by calling console.log on the strength object.
  • strength.calculation_time – This is time spent calculating the strength of a given password. Generally, this will be a few milliseconds.

There are many parameters that we can use for password strength, but we don’t want too much complexity in password validation. So, generally, we will only be using the score parameter of the result. If necessary, we can strengthen the passwords by using crack_time_display or crack_time in conjunction with the score.

Building a Password Strength Meter

We are going to build a reusable password strength meter using jQuery, and will be using jQuery Plugin Boilerplate to maintain a standard structure. The meter can be developed in many ways according to your preference. Some plugins provide the actual password meter widget, while some plugins provide the password strength message, so that users can insert it anywhere they like. We will be focusing on the latter, as it adds more flexibility in designing the password meter. Here are the requirements for our meter:

  • We need basic validations such as checking for empty values and equality of the password and confirm password values.
  • We might need custom validations such minimum characters, blocking certain characters, etc.
  • The actual strength is reported using predefined levels such as very weak, weak, medium, strong, etc.
  • We can use the crack time to implement strength within each of the specified levels.

Implementing Strength Meter Plugin

First, we have to grab a copy of jQuery Plugin Boilerplate from GitHub. Once downloaded, place the file inside your project folder and rename it jquery.password.strength.js. Next, download zxcvbn from GitHub. Include these files in your project file as shown in the following code.

<html>
  <head>
    <title>jQuery Password Strength Checker</title>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
    <script type="text/javascript" src="zxcvbn.js"></script>
    <script type="text/javascript" src="jquery.password.strength.js"></script>
  </head>
  <body>
  </body>
</html>

Now open the jquery.password.strength.js file. I assume you are familiar with jQuery Plugin Boilerplate. First, we have to update the plugin name and default options section as shown in the following code. Here, we have changed the default plugin name to PasswordStrengthManager and replaced the default option with multiple plugin specific options. We have two options for specifying the values of the password and confirm password fields. We also have an array for defining blacklisted words. Next, we have two options called minChars and maxChars for implementing custom validations. Finally, we have an option called advancedStrength to enable or disable the use of crack time to calculate the strength.

var pluginName = "PasswordStrengthManager",
    defaults = {
      password: "",
      confirm_pass : "",
      blackList : [],
      minChars : "",
      maxChars : "",
      advancedStrength : false
    };

Next, we can move into the plugin constructor as shown in the following code. Here, we have the default boilerplate code, apart from the info setting that we have used to keep the message generated by password meter. Once the plugin is used on any HTML element, this function will be called.

function Plugin(element, options) {
  this.element = element;
  this.settings = $.extend({}, defaults, options);
  this._defaults = defaults;
  this._name = pluginName;
  this.init();
  this.info = "";
}

The plugin’s init function is used to initialize plugin specific code and start the process. Let’s take a look at the modified init function (shown below). First, we execute the mandatory validations such as checking for empty passwords and equality of both password fields. this.settings will contain either default values or custom values passed to the plugin initializer. The message for the password meter is stored in this.info. Finally, we set the message to the password meter element passed through the initialization.

init: function() {
  if ("" == this.settings.password || "" == this.settings.confirm_pass) {
    this.info = "Password fields cannot be empty";
  } else if (this.settings.password != this.settings.confirm_pass) {
    this.info = "Passwords doesn't match";
  }

  $(this.element).html(this.info);
},

Next, we move into the custom validators section. Some sites prefer their own restrictions such as character range for passwords or preventing certain characters. We are going to implement two validators for minChars and maxChars. We already defined minChars and maxChars in default settings. These functions will only execute in case we pass a value in initialization. Let’s define functions for these validators:

minChars: function() {
  if (this.settings.password.length < this.settings.minChars) {
    this.info = "Password should have at least " + this.settings.minChars + " characters";
    return false;
  } else {
    return true;
  }
},

maxChars: function() {
  if (this.settings.password.length > this.settings.maxChars) {
    this.info = "Password should have maximum of " + this.settings.maxChars + " characters";
    return false;
  } else {
    return true;
  }
},

These two functions checks for the minimum and maximum character lengths on a given password and return a Boolean value. Next, we need a way to call these manual validations. So we create a function called customValidators as shown in the following code.

customValidators: function() {
  var err = 0;

  if (this.settings.minChars != "") {
    if (!this.minChars()) {
      err++;
    }
  }

  if (this.settings.maxChars != "") {
    if (!this.maxChars()) {
      err++;
    }
  }

  return err;
}

Here, we execute all the custom validators and increment the value of the err variable. As you can see, if conditions will only get executed when the value of the setting is not empty. So, if we don’t pass the parameters on initialization, these validators will not get executed. Finally, call this function as the first line of the init function to get the errors on custom validators.

Calculating zxcvbn Strength

This is the final part of this plugin where we calculate the realistic password strength using zxcvbn. Update the init function with the following code.

init: function() {
  var errors = this.customValidators();

  if ("" == this.settings.password || "" == this.settings.confirm_pass) {
    this.info = "Password fields cannot be empty";
  } else if (this.settings.password != this.settings.confirm_pass) {
    this.info = "Passwords doesn't match";
  } else if (errors == 0) {
    var strength = zxcvbn(this.settings.password, this.settings.blackList);

    switch (strength.score) {
      case 0:
        this.info = "Very Weak";
        break;
      case 1:
        this.info = "Very Weak";
        break;
      case 2:
        this.info = "Weak";
        break;
      case 3:
        this.info = "Medium";
        break;
      case 4:
        if (this.settings.advancedStrength) {
          var crackTime = String(strength.crack_time_display);

          if (crackTime.indexOf("years") !=-1) {
            this.info = "Very Strong";
          } else if (crackTime.indexOf("centuries") !=-1) {
            this.info = "Perfect";
          }
        } else {
          this.info = "Strong";
        }

        break;
    }
  }

  $(this.element).html(this.info);
},

When the custom validators detect zero errors, we move into the realistic strength calculation. We can pass the value of password and blacklisted words defined in initialization process, to the zxcvbn function. It will generate the result with the properties mentioned earlier in this article.

We use a switch statement to filter the score values ranging from zero to four for providing different strength levels. You can change the levels according to your preference. For the first four levels, I have just considered the strength score. Also, we can use the crack_time_display property to further define sublevels. In this plugin, I have only used it for the strength score of four. You can use it for other scores as well.

The crack_time_display value generates the time required to crack the password in a user friendly manner. So, we are breaking the level into two sublevels using the crack_time_display value. If the user decides not to enable advanced strength, the general level called Strong will be used. Feel free to play around with these properties to create advanced password meters.

Finally, we have to modify the last section of the boilerplate code as shown below to enable multiple initializations as we have to execute this function on each key event.

$.fn[pluginName] = function (options) {
  this.each(function() {
    $.data(this, "plugin_" + pluginName, new Plugin(this, options));
  });
  return this;
};

Now we have completed the implementation of the plugin. Let’s see it in action by looking at the following code.

<script type="text/javascript" >
  $(function() {
    $("#pass").keyup(function() {
      initializeStrengthMeter();
    });

    $("#confirm_pass").keyup(function() {
      initializeStrengthMeter();
    });
  });

  function initializeStrengthMeter() {
    $("#pass_meter").PasswordStrengthManager({
      password: $("#pass").val(),
      confirm_pass : $("#confirm_pass").val(),
      minChars : "5",
      maxChars : "15",
      blackList : ["efewf"],
      advancedStrength : true
    });
  }
</script>

We are using a common function called initializeStrengthMeter for initializing the plugin. This function will be called on the element used for the password meter. So, define an empty div element and assign the id of the element to the plugin initializer. Here, we have all the attributes defined in the plugin. You can add or remove them as necessary. Finally, we have to call this on keyup events of both the password and confirm password field to enable the password meter.

Conclusion

In this tutorial, we identified the drawbacks of normal password strength meter and used zxcvbn for realistic strength calculation. We developed a jQuery plugin to handle common use cases for password validation. You can view a demo of this tutorial here and download the source code. Feel free to extend the plugin with your own requirements.

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • http://mrizvandi.com/ mRizvandi

    Thanks for this article.
    Is there any demo page or source at github?