Password requirements: myths and madness

More than 11 years have passed since the venerable XKCD Password Strength strip:

And yet this still happens nowadays on a variety of websites. Maybe it's even more frequent than 10 years ago:

The hilarious part for this website is that the embedded strength checker properly recognizes a good password; but then an additional policy is bolted on, just in case users were too happy. In this case, whitespace is not accepted, and only some non-alphanumeric chars are considered special.

I tried taking a look at those idiosyncratic password requirements, and for most policies I couldn't find a direct relation to some recommendation or compliance. So, here I'm trying to dig in what the underlying reasons are for this folly.

Please use a mix of uppercase and lowercase letters, digits, special chars in your password

Usual explanation: for security reasons you must choose a strong password!

My verdict: Misunderstanding

The usual explanation is correct, but does not imply that a password should contain a lot of strange, hard-to-type and hard-to-remember characters. That's exact what xkcd passwords are about: a longer password with plain ascii lowercase letters can have the same entropy as a shorter password from a larger charset.

If you host a web application: Enforce a password's strength, not strange user-hostile policies. There're libraries for that (e.g. https://github.com/dropbox/zxcvbn) that work both in backend and frontend.

You cannot use whitespace, accented letters, hyphens, [...] in your password

Usual explanation: Very often there's no explanation for this, or it's something like "your password contains unsafe characters".

My verdict: No real motivation beyond, possibly, incompetence

This is a terrible one. You waste a lot of time at generating a "strong password" that complies with a website's policy, and then you discover that you could not use "-" in it. Or just whitespace for XKCD-style passwords.

There's no technical reason for restricting any character from appearing in any password. The usual approach for handling a password is:

  • take the password as a string, as the user typed it;
  • Prepare it (see links at the end of the paragraph);
  • encode with a specific, well-defined encoding (e.g. utf-8);
  • add a salt (probably your favourite library will require it in its input) and use a password-derivation algorithm (pbkdf2, Argon2, whatever) to get an "hashed" password and save that salt+hash in your storage of choice.

What I suspect is that improper escaping and/or encoding techniques are being used in a website imposing that restriction. It's a red flag.

Caveats:
In some case there can be UX reasons for limiting the input charset, especially regarding special chars. Maybe you don't want people to use chars that cannot be found on some keyboards, because then, if people move across the world and use different computers, they're unable to enter their password. Or maybe the keyboard layout isn't yet set when the password is entered (example: full disk encryption password at boot) and you risk that a user is entering a password at install time, but what they write at boot is actually different. Maybe newline or other control chars are an hassle.

If you host a web application: make sure you're correctly processing the string coming from the user, rather than adding arbitrary requirements that force the users back-and-forth from a password manager to your application.

EDIT:
Commenters on HN correctly noticed that I forgot a passage when handling passwords, the so called "string preparation". It doesn't really matter too much with what we're dealing here, but here are some links:
https://withblue.ink/2019/03/11/why-you-need-to-normalize-unicode-strings.html
https://www.rfc-editor.org/rfc/rfc8265
http://unicode.org/reports/tr15/#Stabilized_Strings

So, it appears (Unicode is a terribly large and complicated standard, I may have misunderstood something) there could be good reasons to reject some input chars since there could be no stable encoding under any normalization process. But it doesn't seem the case in the scenarios I've seen.

You cannot enter a password with fewer than X chars

EDIT: it seems that the message in this paragraph was widely misunderstood; I've changed the wording. Dec 23 2022, 17:15 CET

Usual explanation: security! I want your password to be veeeery strong!

My verdict: Makes sense, but could be better, and if X is too large, it's just annoying.

This is the exact opposite of the first point. Sometimes you get a 16 or 20 minimum length for the password. Why? If I'm autogenerating a password with all-possible-and-incredible-chars, eight should be enough. NIST standards even allows just 6 chars in some situations (check 5.1.1.1 Memorized Secret Authenticators).

This is connected with password strength. A short alphanumeric password is usually easy to bruteforce with adequate money and gpu resources.

But, still, a website should aim at password strength, not at password length. If I use four unicode code points out of the more-than-one-million available, by picking those outside the BMP, my password is probably very safe already, since there are (10**6)**4 possible passwords, many more than (127**8), which is more-or-less the number of possible ascii-printable passwords with 8 chars.

If you host a web application: probably your password strength checking library is not so good at understanding strange Unicode code points, so, you'll better go for a minimum length, but don't go wild: 8 or 10 with a password strength checker is the way to go. And: always clearly state the minimum length which is required for a password.

You cannot enter a password with more than X chars

Usual explanation: whew. It's too large we cannot handle it.

My verdict: Largely unmotivated unless X is quite large.

Once hashed, passwords take up the same amount of space. Restricting the maximum number of chars to a low number makes no sense and then forces people to use strange chars to get complexity right.

This is especially troublesome when the browser field is short, you can't see the password that you're pasting because it's masked, and you finally set a password that's not the one you expect. Then, when trying to login, the "enter your password" field isn't got the same limitations, and you cannot login because you're using the wrong (too-long) password.

Caveats:
An higher length limit for passwords must should exist to prevent DoS to an app, but should be rather high, like, not lower than 64 chars. Also, some algorithms that were (and maybe still are) quite common for password verification, like blowfish, don't properly work beyond 45 chars or so. Still, that's not the far-too-common 12 or 16 chars that can be found on plenty of websites.

EDIT:
A reader pointed out that properly-implemented password hashing algorithms aren't really subject to DoS. But, you may not be 100% sure about your implementation quality, and a a longer password doesn't mean it's necessarily more secure.

If you host a web application: please allow long passwords at least 64 chars long; even 256 should pose no DoS risk whatsoever. Also, make sure that the HTML field itself is larger than the allowed password size, so you can tell the user "password too long" if they're pasting into it.

You cannot paste into this field

Usual explanation: Security! I want you to actually write this and know what you're writing and write it twice in two boxes! Don't copy-paste from somewhere else!

My verdict: Largely unmotivated right now, and dangerous.

Somebody thinks that disallowing paste is a good idea so people actually need to write a password twice and they can't make typos. But this prevents using password managers, which are a Good Idea. This is a very old thing that some people thought being a good idea in the past, but I think it's not considered ideal since.... 2005?

If you host a web application: please allow pasting into password fields.

You cannot show or copy this field

Usual explanation: security! your password is For Your Hands Only. We cannot even trust your eyes.

My verdict: Security through obscurity bad idea.

Don't do this. While setting a password, there must be an icon to show it and make sure I'm not doing mistakes. It won't be saved in plaintext anywhere else! This is especially true if you're not allowing pasting a password. Then there's no way to make sure I've written what I wanted to write! The default masking of the password is just designed to prevent shoulder surfing.

If you host a web application: please allow showing what I entered when setting or entering a password anyway. Otherwise I can keep doing mistakes!

EDIT:
This entry was edited after some comments. I know that's not what "security through obscurity" mean, it was a kind of joke about "obscurating" the password.

Your password has expired

Usual explanation: used to be widespread, and even required and recommended by widespread operating systems and applications.

My verdict: Old idea

This once happened to be recommended, because a leak of password hashes was considered possible, and the password was in plaintext or was using weak hashes, and reuse was frequent. Nowadays, it's not recommended any more: unless there has been a known leak, if the password is properly salted and hashed, has a reasonable complexity, and hasn't been reused, there's no need fo rotation

Too many failures - your account is locked.

Usual explanation: we don't want your account to be bruteforced

My verdict: Bad idea especially if "too many" is low, like 3 or 5, and my password is complex.

The idea is that you "protect" a user preventing their account being bruteforced. But the CIA triad includes Availablity, and you're basically opening a giant door for a DoS this way; just know somebody's username and you can lock their account. Who knows what it takes to unlock it.

Account locking could be used in 2FA contexts (requires the other factor to provoke a DoS - that's why in some cases you enter a wrong password and you're still asked for your second factor, and only at the end you fail the authentication if either was wrong), but it's still usually pointless to lock an account after a few attempts - they're too few to guess a password.

Caveats:
Some compliance policies require locking user accounts.

If you host a web application: consider using temporary locking with exponential, kind-of-stochastic backoff (like 10s wait the first time before being able to enter the password again, 22s the second...) after 10-20 attempts instead. If you can, it's probably useful to limit this measure to specific IPs that are attempting the bruteforce (but can be hard if it's a distributed attack).

Final thoughts

I really hope that passwordless login will make some steps forward in the next years (e.g. https://passkeys.dev/, https://www.yubico.com/authentication-standards/fido2/). In the meantime, I'd love a "password complexity api" so that my browser (or password manager) can already generate the right password for a website.

References

https://www.auditboard.com/blog/nist-password-guidelines/
https://pages.nist.gov/800-63-3/sp800-63-3.html