Modern web applications have a responsibility to prevent their users from using easily compromised passwords. I would also say that it’s in their best interest, although it’s certainly a trade off. Most people still don’t use password managers, so stricter requirements will lead to some people losing access to their accounts. Still though, forcing people to use even moderately strong passwords will help prevent account takeovers and all the headaches that go along with them.
I’ve compiled a list of some things I think all apps should do to enforce strong passwords. The thresholds you pick will depend on the security requirements for your system.
Rate Limits
Login attempts should be rate limited. While not strictly related to enforcing strong passwords, rate limits will enhance the effectiveness of the other techniques. Indeed, rate limiting is identified as an OWASP Top 10 security risk for APIs.
Minimum Length
Checking the password length is primarily an optimization for the next steps. I don’t believe in complex password rules, but it goes without saying that short passwords are easy to guess. Length is a cheap thing to check before we get into the more complex analysis.
Check Strength
Instead of complex password rules, we can use an algorithm like zxcvbn to evaluate the passwords. The idea here is to forgo annoying rules and instead focus on the complexity of the password itself. This has shown to be more user friendly and more secure at the same time.
Bonus: Pwned Passwords
Finally, you may want to block passwords that have been found in publicly exposed password lists. Troy Hunt’s Pwned Password API makes this very easy. There are some drawbacks of this that might be a none started for some applications — namely, your password change process now relies on a third party API. It’s also debatable whether globally blocking nearly a billion passwords is useful. Luckily, the API includes information about how many times a given password has been seen in breaches, so it’s possible to fine tune this as well.