Passwords one of the most frequent ways that we use to access our digital accounts. Having secure passwords is really crucial, and represents one of the most important aspects that we need to pay attention to. As developers, we also need to make sure that we provide our services with a high level of security. Last year 2017 NIST (National Institute of Standards and Technology) recommended to check user passwords against existing public breaches of data, and fortunately, there exists an API that allows you to do that really easily.
The Pwned Passwords API is a service that you can use to check whether a password has been exposed as part of a number of numerous data breaches that have occurred several times in the past. These data contain more than 500,000,000 passwords that have been used before.
You can install this in your Ruby applications using the following gem as a wrapper:
gem 'pwned'
After you have installed it, you can create a new this Pwned::Password object and then check if it has been breached:
password = Pwned::Password.new("password")
You can also check how many times the password appears in the dataset.
password = Pwned::Password.new("password")
<span style="font-weight: 400;">password.pwned_count</span>
<span style="font-weight: 400;">#=> 3303003</span>
As you may probably be using this service as part of the sign up process, you are supposed to also take into consideration the fact that this service may not be working sometimes:
begin
<span style="font-weight: 400;"> password = Pwned::Password.new("password")</span>
<span style="font-weight: 400;"> password.pwned?</span>
<span style="font-weight: 400;">rescue Pwned::Error => e</span>
<span style="font-weight: 400;"> # Ummm... don't worry about it, I guess?</span>
<span style="font-weight: 400;">end</span>
You can also make this API call a lot easier using the following:
Most of the times you only care if the password has been pwned before or not. You can use simplified accessors to check whether the password has been pwned, or how many times it was pwned:
Pwned.pwned?("password")
<span style="font-weight: 400;">#=> true</span>
<span style="font-weight: 400;">Pwned.pwned_count("password")</span>
<span style="font-weight: 400;">#=> 3303003</span>
You can also validate your models like the following:
class User < ApplicationRecord
<span style="font-weight: 400;"> validates :password, not_pwned: true</span>
<span style="font-weight: 400;"> # or</span>
<span style="font-weight: 400;"> validates :password, not_pwned: { message: "has been pwned %{count} times" }</span>
<span style="font-weight: 400;">end</span>
You can even set a threshold that you believe should be used to warn a user about a password that has been breached. For example, you may think that a password that has appeared only 2 times is not a problem:
class User < ApplicationRecord
<span style="font-weight: 400;"> # The record is marked as valid if the password has been used once in the breached data</span>
<span style="font-weight: 400;"> validates :password, not_pwned: { threshold: 2 }</span>
<span style="font-weight: 400;">end</span>
If you are using Devise for your authentication, there is another specific gem prepared specifically for this.
You can learn more about this gem and its implementation by visiting its Github page.