django-pwned-passwords

pwned.

On August 3rd, Troy Hunt released a new addition to the popular ';--have i been pwned? service - a website that tells you if your user information such as an email address has been involved in a major security breach in the past.

Troy announced the addition of 306 million pwned passwords. This data set will allow the public to analyze new passwords to ensure they have not been involved in a similar breach to those reflected by the classic service.

pwned passwords matter

Some of the most popular attack vectors leverage lists of common passwords or dictionaries of common words and substitutions to identify a user's password and gain malicious access to an account. For those malicious users, lists of passwords are a great resource, as many people use the same password for multiple services, or in the case of simple passwords like P@ssw0rd, the same password as each other.

The mere presence of this dataset screams security nightmare for users that secure their accounts with one of the passwords on that list. I don't necessarily recommend typing your password into someone else's website, but you can download the data set too and cross reference your personal data with that list.

That said, when creating new accounts, it's important to ensure that these accounts are not using already-pwned passwords. To aid in this, Troy has released an API to determine if a password was found in the set.

Django integration

As an avid Django developer and a (junior) security enthusiast, I figured I'd build a small integration to allow Django user registrations to cross-reference that list of passwords.

For the last day or so, I've been working on django-pwned-passwords, a package that provides a Django password validator that will cross reference the password of new registrants with that list. You can read more over at Github or Read The Docs. For a quick installation:

Install django-pwned-passwords::

$ pip install django-pwned-passwords

Add it to your INSTALLED_APPS:

INSTALLED_APPS = (
    ...
    'django_pwned_passwords',
    ...
)

Add django-pwned-passwords's PWNEDPasswordValidator:

AUTH_PASSWORD_VALIDATORS = [
    ...
    {
        'NAME': 'django_pwned_passwords.password_validation.PWNEDPasswordValidator'
    }
]

Disclosure

This app currently sends user passwords to a third party. There are obvious security risks associated with this practice.

There are a few practical issues with this implementation. First, the rate limiting of the API is pretty strict (one request per 1500ms per IP). This means that a fail-safe solution is likely required, which will simply allow passwords through when the server is being rate limited. That means that by default, not all passwords may be validated.

The other, perhaps more important issue is that you're still sending passwords to a third party. There are definitely concerns around this. The purpose of this application was more to experiment with the possibilities of Django's password validators and increase awareness of the importance of password strength.

Next Steps

To help resolve some of these issues, I'm considering an implementation that will include the entire data set with the source code (somehow - it's huge) and provide a small Django API with the package that can be used to perform the check. If you've got any other ideas that can help make this app more practical, please let me know!