Strong Passwords: Education not enforcement
A website I'm working on allows the user to choose passwords, and also can suggest passwords for the user. I'm fully in control of this program and its password generation and checking strategies, I started to think about what would make the best strategies.
Here are some constraints which I've seen on various systems:
- Passwords must have at least one lower-case, one upper-case, one digit character
- Some passwords must also include special characters such as "!", "$" etc.
- Passwords must be longer than a certain length
- Passwords must be not longer than a certain length
- Passwords are not displayed on the screen, but replaced by **s
- Case is significant (If you create your password with "A" and enter it as "a", it's wrong)
But here are some observations:
- If you read or write down a password, you're going to get the digit 0 and the letter O confused, etc.
- If you have the Caps Lock key pressed accidentally, you're going to type the password in capitals by mistake. You won't even notice because there are only **s on the screen. (Some systems e.g. Windows get around this by warning you, but websites can't give such warnings)
- If you are typing on a foreign keyboard, then "!" and "$" are almost certainly somewhere else, or might not even be available. You are going to type them wrong. You won't even notice because there are only **s on the screen
- Obviously the longer and the greater the set of allowable characters, the greater the space to be searched in case of a brute-force attack. I have no doubt that's why case sensitivity is considered a good thing. And obviously minimum lengths.
- If you enforce too many rules, and the user finds it difficult to find a suitable password, they're going to write it down and stick a post-it to their monitor, or add it to "passwords.doc" on their desktop. Such a situation decrease, not increases, password security.
- Humans will strive to get around rules. If they want to use weak passwords, they will. For example I knew someone on a system which didn't allow the last 5 passwords to be used again. So he simply changed his passwords to "a", "b", "c" etc. until it had forgotten the last 5 passwords so he could use the one he wanted.
So here are my recommendations:
- Allow the option for the user to see their password, check a checkbox to see "abc" not "***". Like on mobile phones. Usability is increased for the case there is nobody standing behind the user's PC (the normal case).
- Consider upper-case and lower-case to be the same. (Normalize passwords to lower-case when hashing them and comparing them)
- Consider the letter O and the digit 0 etc to be the same. (Replace all letter Os with digit 0s, etc. before hashing them and comparing them)
- No maximum length
- No forbidden characters. If they want to use "!" then they should be able to do so, as it might be a character in their favorite password, and we don't want the post-it note situation. But don't force them, for the same reason.
- Education is more important than rules (as rules will be got around). Point out what will happen once their account gets compromised. Point out how longer passwords are better, pet's names aren't good, etc.
- Generating a password? Generate a long one (16-20 chars), upper-case only (easier to read in case you write it down), no special characters (problems with keyboard layouts)
I'm not sure about minimum length. I mean if there are no rules about mandatory characters, and if the system is case insensitive, then without a minimum length users could simply type in "a"? But minimum length might prevent a user from using a password they already know. And given users won't accept rules, if one enforces a minimum length then users will just use 10x "a" or "12341234....". I think, again, education is the key here.
Clearly another option is not to maintain passwords at all but e.g. use a SSO system like oauth with a provider who does maintain passwords e.g. Facebook. But then one is giving a certain amount of power to those providers, and perhaps one doesn't want to do that.
Yet another alternative, given there'll be some "reset password via email" link, is just to say, ownership of the email address is sufficient to indicate authorization. I mean that certainly is the case if you provide such a link; so why not only provide such a link? Every time the user logs on, allow them to type in their email address and click a button, a one-time link gets delivered to their inbox.
Off-topic: For password hashing, use bcrypt, which can be made to deliberately take a long time, to thwart brute-force attacks against your hashed passwords in case of a database leak.