Relaxing Ory Kratos's password breach check
Ory Kratos checks proposed passwords agains haveibeenpwned. In this post, we get Kratos to relax, just a little bit, to make passwords usable again.
Ory Kratos is an identity provider, authentication and session management software. In this post I explain how to get Kratos's haveibeenpwned password breach check to chill out, just a little bit!
Background
Kratos is an IDP / login provider. Users can sign up and authenticate using password based authentication (among others). As part of the signup, recovery, and change password workflows, Kratos checks the user's proposed password with the haveibeenpwned API.
By default, if the proposed password has been found in any breach, then Kratos rejects the password.
The Problem
In our experience we have found this to be a pretty major barrier to account creation and password recovery. The breached password list contains hundreds of millions of passwords, and this continues to grow.
Taken to the extreme - eventually every reasonable password will be in there, at which point no passwords can be used.
Already we get support requests from people who are trying to do the right thing, making passwords they think are reasonable, but that have been found in a breach. It's frustrating for them, and you can't really give a good answer to support - just try a different password until you get one that works.
The Security Justification
Checking proposed passwords against known bad passwords is an Excellent Idea. Password reuse across sites means that a leaked password on one service is likely to make another service vulnerable. NIST recommends it:
It is recommended that passwords chosen by users be compared against a “black list” of unacceptable passwords. This list should include passwords from previous breach corpuses, dictionary words, and specific words (such as the name of the service itself) that users are likely to choose.
However, in it's latest version of SP-800-63b, they provide further guidance:
Verifiers SHALL implement a rate-limiting mechanism that effectively limits the number of failed authentication attempts that can be made on the subscriber’s account
The breached password check is just one part of password security, and should be used in conjunction with others including rate limiting login attempts.
With that in mind, you may consider a tradeoff - the password breach check is really there until rate limiting and other checks kick in. If attackers are more likely to try more common passwords first, then you may not need to check against every password ever leaked, just the ones that appear in the most breaches.
This is actually an approach suggested by Troy Hunt, the author of haveibeenpwned. I'm going to quote the whole bit here:
Now on the one hand, you could argue that once a password has appeared breached even just once, it's unfit for future use. It'll go into password dictionaries, be tested against the username it was next to and forever more be a weak choice regardless of where it appears in the future. However, I got a lot of feedback from V1 along the lines of "simply blocking 320M passwords is a usability nightmare". Blocking half a billion, even more so.
In V2, every single password has a count next to it. What this means is that next to "abc123" you'll see 2,670,319 - that's how many times it appeared in my data sources. Obviously with a number that high, it appeared many times over in the same sources because many people chose the same password. The password "acl567", on the other hand, only appeared once.
Having visibility to the prevalence means, for example, you might outright block every password that's appeared 100 times or more and force the user to choose another one (there are 1,858,690 of those in the data set), strongly recommend they choose a different password where it's appeared between 20 and 99 times (there's a further 9,985,150 of those), and merely flag the record if it's in the source data less than 20 times. Of course, the password "acl567" may well be deemed too weak by the requirements of the site even without Pwned Passwords so this is by no means the only test a site should apply.
Getting Kratos to Relax
Ory's docs are often frustratingly lacking. Their docs on this password check only explain how to turn it off. However, if you actually go into the config file schema, you can find some more settings.
methods:
password:
enabled: true
config:
haveibeenpwned_enabled: true
max_breaches: 100
ignore_network_errors: true
min_password_length: 8
identifier_similarity_check_enabled: true
More settings for haveibeenpwned
The important one here is max_breaches
. Once set, Kratos will only reject a password if it has been found in at least that many breaches, giving you functionality similar to what Troy describes above.
If you are using Kratos with password authentication, and you find your users struggling to set passwords, then consider relaxing this configuration if your security posture and risk assessment allows it.