Menu Navigation Menu

Building secure web applications is really, really hard. One of the biggest attack vectors in modern webapps is passwords. Even if we set aside the dangers of phishing or other more sophisticated attacks, passwords themselves are a source of danger, between simple passwords, guessable passwords, shared passwords among family members or teammates, and reused passwords across accounts.

Security teams have traditionally responded to the dangers inherent in passwords by imposing onerous rules and requirements: perhaps your password has to be between 6 and 15 characters, must contain at least one number, at least one uppercase letter, at least one lowercase letter, and at least one symbol. (Even worse, there’s usually a secret list of forbidden symbols they won’t show you until you try to use one, which happens to me all the time.)

In higher security environments like workplaces or banking, it’s very common to make things even worse by expiring passwords every 90 (or even every 30!) days, as well as tracking previous passwords to ensure that previous passwords are never used again.

Unfortunately, all the research we have about password policies indicates that they don’t help with security. At all.

Punishing users with harsh requirements most commonly results in a sticky note underneath the keyboard or even stuck to the side of the monitor with the latest password written on it for anyone to see—which completely defeats the point of passwords in the first place.

Instead of brutal password requirements that defeat their own purpose, follow the evidence-based guidelines issued by the National Institute of Standards and Technology. The full document isn’t hard to understand, and their recommendations are clear:

  • Never require special characters, including upper, lower, digit, or symbol
  • Never prohibit certain characters
  • Never automatically expire passwords
  • Never allow passwords that have previously been exposed in a data breach

In the digital wastelands of 2018, there have been so many data breaches that it is that last requirement that truly keeps your users’ accounts safe and secure. Using a password that has been leaked in a previous breach means that it will be easy to guess or brute force, because it’s already out there in lists of passwords to try.

Simply blocking passwords that are known to have been leaked means that your users will have the highest possible protection a password can offer: only a keylogger or a brute force attack from scratch can break into their account.

With inspiration from the pwned gem, the Java library passpol, and the Javascript library nbp, we’ve created a library you can use to follow the NIST password guidelines (and keep your accounts safe) without punishing your users with impossible password guidelines: unpwn.

The unpwn gem takes a hybrid approach to validating passwords. First, it checks the proposed password against the top one million most common passwords extremely quickly, and with no network requests, by using a bloom filter.

Bloom filters are both very cool and an extremely good fit for this particular problem. We want to know if the proposed password is included in the top one million leaked passwords, but that list is almost 100mb and checking passwords against it would take a long time. The bloom filter included with this gem is only 1.7mb, but allows us to check passwords as if we had the entire top one million list available locally.

If the proposed password passes the bloom filter check, the gem then uses the pwned gem to make a call to the haveibeenpwned API.

The haveibeenpwned API offers the most comprehensive public database of leaked passwords in existence, and the API is very clever. Your application doesn’t send the possible password to the API. Instead, it hashes the password and sends just the first few characters of the hash. The API returns all of the known password hashes that start with those characters, and your application can then check to see if the proposed password is one that has already been hacked in the past.

Give unpwn a try today, and keep your users safe without punishing password rules. We plan to add direct integration with Devise in the future. If you try it out, or you have ideas for how to improve unpwn, we’d love to hear from you!


Andre, Cloud City Development Senior Developer, known for well-tested code that's maintainable over time, thinks every new feature is a chance to leave the codebase in better shape than it started. For over 12 years, he's built and run web applications and specializes in sharing knowledge via pairing. He's been the lead developer of Bundler, the Ruby dependency manager, for more than 5 years; co-authored the third edition of The Ruby Way, a book about how to use Ruby in an idiomatic way; and founded Ruby Together, the non-profit Ruby Trade association. No matter what software you need to build, chances are good that he'll be able to give you specific examples of the tradeoffs to keep in mind, and help your company choose the options that will make you the most successful.


Got a question about ruby dependency management?

Or need a second pair of eyes on your Rails app?

Contact us today for a complimentary 30 minute consultation.

get in touch