Register by 10/16 for $250 off the on-site price.
Build the future of communications.
Start building for free

Round up: Libraries for checking Pwned Passwords in your 7 favorite languages

ySHxI-gQII7uqLxqbAg9CSDY7Ii3rQmDuTLIyMIIFQRijKMlxZR1Y-OKmqj2gOifoI2XIgck4v29K6b5_WfXSQqoAMf9SpCY9iI9a8MCHeUjMa5rEKdqpj9G-Ge1ZEzyql__zVmU

Earlier this year Troy Hunt released version 2 of his popular Pwned Passwords API service. The new version comes with even more compromised passwords and a more secure way to query the password API that doesn’t require sending plain text passwords over the network.

The API update comes at a good time. When NIST updated its password guidelines in 2016, it included a new recommendation to check “memorized secret verifiers”, or passwords, against known data breaches:

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.

Since the API release, the community has created API wrappers in many of our favorite programming languages. In this post, I round up the libraries in 7 languages. Read through to learn more about each or jump ahead to your language of choice:

The Problem with Pwned Passwords

People reuse passwords. And they use passwords that are short and easy to guess. This is a problem because even if you don’t care if your Myspace account gets hacked, if you were using the same password there as you are for your email or your bank account, you’re gonna have a bad time.

That’s because hackers will use those leaked credentials to gain access to your other accounts in a process known as credential stuffing. It’s still common practice because bad actors can make a lot of money doing this. And it’s one of the reasons we’re big fans of Two-factor Authentication.

For example, the password password1 has been seen over 2 million times according to haveibeenpwned.

If you want to take advantage of the haveibeenpwned data you can access it directly from the API or use one of the following client libraries.

Ruby

Our very own Phil Nash created a Ruby gem to wrap the API. You can read all about better passwords in Ruby with the Pwned Passwords API or check out the pwned gem on GitHub. Install the gem with the following command in your terminal:

gem install pwned

Once installed, fire up an irb -r pwned session and test it out with your password of choice:

> Pwned.pwned?("password1")
#=> true
> Pwned.pwned_count("password1")
#=> 2310111

For more details, make sure to check out Phil’s full blog post.

Python

The kind folks at Lionheart developed the wrapper for Python. Their tool works both as a CLI and a Python library. You can check out the pwnedpasswords Python library on GitHub. Install the library using pip:

pip install pwnedpasswords

Fire up the python REPL and type the following to test it out:

import pwnedpasswords
pwnedpasswords.check("password1")
# returns 2310111

Java

Over in JVM-land @nbaars has us covered with a Java library. Check out  pwnedpasswords4j over on GitHub.

To use the library, create a new project using Maven with the following command:

mvn archetype:generate -DgroupId=com.twilio.pwned -DartifactId=pwned -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

And add the project as a dependency to the pom.xml file:

<dependency>
  <groupId>com.github.nbaars</groupId>
  <artifactId>pwnedpasswords4j-client</artifactId>
  <version>1.1.0</version>
</dependency>

The following is a simple Java program that checks our example password. Copy it into your App.java file.

package com.twilio.pwned;

import com.github.nbaars.pwnedpasswords4j.client.PwnedPasswordClient;
import com.github.nbaars.pwnedpasswords4j.client.PwnedPasswordChecker;
import okhttp3.OkHttpClient;

public class App
{
    public static void main( String[] args )
    {
        PwnedPasswordClient client = new PwnedPasswordClient(new OkHttpClient(), "https://api.pwnedpasswords.com/range", "");
        PwnedPasswordChecker checker = new PwnedPasswordChecker(client);
        boolean result = checker.check("password1");

        System.out.println( result );

        System.exit(0);
    }
}

Run the file using your IDE or from the command line with the following commands:

mvn package
mvn dependency:copy-dependencies
java -cp target/pwned-1.0-SNAPSHOT.jar:target/dependency/pwnedpasswords4j-client-1.1.0.jar:target/dependency/okhttp-3.10.0.jar:target/dependency/okio-1.14.0.jar  com.twilio.pwned.App

You can also add build configuration to your pom.xml for the maven-jar-plugin so that mvn package will create a single jar file with all of your dependencies. You can see how I did that here. Once you add that, you can run it from the terminal with java -cp target/pwned-1.0-SNAPSHOT-jar-with-dependencies.jar com.twilio.pwned.App.

PHP

In a new folder, use Composer to install Maxweb’s PHP wrapper for PHP 7 or higher:

composer require ron-maxweb/pwned-passwords

Then create a new file called, I called mine pwned.php and add the following code:

<?php

require './vendor/autoload.php';

$pp = new PwnedPasswordsPwnedPasswords;
$password = 'password1';
$count = $pp->getCount($password);

echo $count . "n";

Now you can run the file from your terminal with the following command:

php pwned.php

Check out the PHP code on GitHub for more information.

Node

Over in Javascript land I found a handy Promise-based Node.js wrapper for the API. Install via npm:

npm install save hibp

Open up the Node REPL and test it out to see how many pwns your password has.

var hibp = require('hibp');

hibp.pwnedPassword('password1').then(numPwns => console.log(numPwns))
// 2310111

Read more about the Node.js hibp library and its additional functionality on GitHub.

C#

If you’re a .NET user and/or a C# fan there are several options out there, but let’s look at Andrew Locks implementation in a .NET Core 2.1 project..

Create a new .NET Core Console App in Visual Studio or by using the dotnet CLI.

dotnet new console -o pwnedPasswords
cd pwnedPasswords

Next install two Nuget packages:

into your project using your favorite Nuget package install method. Finally, before we get to some code, let’s make one small change to the project file to tell .NET Core to use the latest C# compiler.  Open the pwnedPasswords.csproj file and add the following to the ProjectGroup element:

<LangVersion>latest</LangVersion>

Great. Now replace the code in Program.cs with the code below.

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using PwnedPasswords.Client;
using System;
using System.Net.Http;
using System.Threading.Tasks;

namespace pwnedPasswords
{
    class Program
    {
        public static async Task Main(string[] args)
        {
            var services = new Microsoft.Extensions.DependencyInjection.ServiceCollection();
            ConfigureServices(services);

            var provider = services.BuildServiceProvider();

            var app = provider.GetService();
            await app.Verify("password1");

        }

        private static void ConfigureServices(IServiceCollection services)
        {
            services.AddTransient();
            services.AddLogging();
            services.AddPwnedPasswordHttpClient();                      // add the client to the container
        }
    }

    public class Application
    {
        IPwnedPasswordsClient _client;

        public Application(IPwnedPasswordsClient client)
        {
            _client = client;
        }

        public async Task Verify(string password)
        {
            var result = await _client.HasPasswordBeenPwned(password);
            Console.WriteLine(result);
        }
    }
}

This code uses the built in Dependency Injection container in .NET Core to inject a new instance of the PwnedPasswordsClient into the Application class. Calling the Verify method uses that instance to check if the password has been pwned and prints the result to the console.

Run the project in Visual Studio or from the CLI using  dotnet run.   You should see that the default password we are checking password1 is indeed pwned.  Stop the project and change the value passed into the Verify method to see if you can get a different result. See the code for the full console app over on my GitHub.

While using the PwnedPasswordsClient is pretty cool on its own, as Andrew outlines in the detailed README, you can *also* use his library as part of your Identity Validator by adding it to your Identity builder.

Golang

The Go client library from Matt Evans provides an interface for checking if a password has been pwned or not. It’s lightweight, but effective. Check out the code for the Go client on GitHub.

Install the library:

go get -u github.com/mattevans/pwned-passwords

Add the following code to a file called pwned.go

package main

import (
        "fmt"
        "os"

        hibp "github.com/mattevans/pwned-passwords"
)

func main() {
        client := hibp.NewClient()

        password := "password1"
        pwned, err := client.Pwned.Compromised(password)
        if err != nil {
                fmt.Println("Pwned failed")
                os.Exit(1)
        }

        if pwned {
                fmt.Printf("'%s' is pwned!", password)
                fmt.Println()
        } else {
                fmt.Println("You're all clear.")
        }
}

Run the file with the following command:

$ go run pwned.go
'password1' is pwned!

Don’t Get Pwned

You can always check your passwords against the web interface at https://haveibeenpwned.com/Passwords. If you find your creds have been breached, make sure you change your passwords and start using a password manager to prevent duplicate credentials.

Checking passwords against breached credentials is just one of many ways application developers can protect their users. I wrote about other ways to enforce better passwords here. You can also check out my synthesis of the updated NIST guidelines for better passwords on my GitHub.

To guard against potential security breaches *always* use 2FA when available. Be a good security samaritan and add it into the websites you develop – we at Twilio happen to have an API for that.

Do have another library to contribute? Leave me a note on Twitter with any thoughts, questions, or security puns @kelleyrobinson

Sign up and start building
Not ready yet? Talk to an expert.