Prevent users registering with passwords from data breaches

Posted on 15th December 2018 - Takes 4 minutes to read


It is generally recommended that developers of web applications ensure their users pick decent passwords. This offers means ensuring a minimum length, preventing common passwords, or words from the dictionary. Sometimes users need to mix and match various numbers, letters, and symbols too.

But we can do better.

Checking passwords against previous breach corpuses

Several of my open source packages focus around password security. The most popular of which let developers check their users' passwords, to ensure they have not been exposed in 3rd party data breaches. This is a very important protection to have in place considering one of the primary ways online accounts are compromised is via password reuse.

Checking passwords against previous data breaches is also recommended by the National Institute of Standards and Technology. See the quote below, from NIST Special Publication 800-63B section 5.

When processing requests to establish and change memorized secrets, verifiers SHALL compare the prospective secrets against a list that contains values known to be commonly-used, expected, or compromised. For example, the list MAY include, but is not limited to:

  • Passwords obtained from previous breach corpuses.

Packages

Here are a few open source PHP & Laravel packages that implement secure password exposure checking functionality.

Password Exposed Helper Function

If you're developing a pure PHP web application, you'll want to use the Password Exposed Helper Function package. This package provides a simple password_exposed method which you can pass a password in order to determine whether it was previously exposed in a data breach.

Here's an example of how you can use it in your web application:

switch(password_exposed('hunter2')) {

    case PasswordStatus::EXPOSED:
        // Password has been exposed in a data breach.
        break;

    case PasswordStatus::NOT_EXPOSED:
        // Password has not been exposed in a known data breach.
        break;

    case PasswordStatus::UNKNOWN:
        // Unable to check password due to an API error.
        break;
}

Laravel Password Exposed Validation Rule

If you're using the Laravel framework, this is the package for you. This package ties into to the built-in Laravel validator, providing a custom rule. This custom rule will check if the provided password field contains an exposed password, and if so, returns a customisable, validation message.

Using this validation rule is quite simple, as shown below. It can be used within a controller, or request object, in the same way as any other Laravel validation rule.

use DivineOmega\LaravelPasswordExposedValidationRule\PasswordExposed;

$request->validate([
    'password' => ['required', new PasswordExposed()],
]);

Check out the Laravel Password Exposed Validation Rule readme on GitHub for additional documentation.

Laravel NIST Password Rules

I wrote the Laravel NIST Password Rules package for Langley Foxall, who specialise in bespoke enterprise software solutions. This package is now included by default in all new Laravel powered projects, ensuring high security by default policy is in place.

This package provides Laravel validation rules that follow the password related recommendations found in NIST Special Publication 800-63B section 5. Currently, it provides validation rules for the NIST following recommendations.

Recommendation Implementation
[...] at least 8 characters in length A standard validation rule in all rule sets to validate against this minimum length of 8 characters.
Passwords obtained from previous breach corpuses The BreachedPasswords rule securely checks the password against previous 3rd party data breaches.
Dictionary words The DictionaryWords rule checks the password against a list of over 102k dictionary words.
Context-specific words, such as the name of the service, the username The ContextSpecificWords rule checks the password does not contain the provided username, and any words defined the configured app name or app URL.
Context-specific words, [...] and derivatives thereof The DerivativesOfContextSpecificWords rule checks the password is not too similar to the provided username, and any words defined the configured app name or app URL.

How does checking for password exposure work?

All these packages make use of the Have I Been Pwned - Pwned Passwords API, created and ran the security expert, Troy Hunt.

This API allows you to securely check for password exposure, without exposed the password. It works by sending the first few characters of the password's SHA1 hash to the API endpoint. The response contains a large list of all exposed SHA1 hashes that start with that prefix, allowing these package to locally check whether the password has been exposed.

This type of implementation, which allows for searching by partial hashes, is known as a k-anonymity model.

If you have any questions regarding these packages, feel free to contact me on Twitter.


open source security PHP password_exposed laravel-password-exposed-validation-rule passwords data breaches NIST laravel-nist-password-rules