The usability of web forms is a subject that has been discussed extensively, and one which is supported by a large body of literature (1, 2, 3, 4). The consensus is that getting web forms right is much harder that it may initially seem. One aspect that particularly annoys me is the way most developers implement passwords and their validation.
Despite the emergence of single sign-on systems like OpenID, most users are still affected by so-called password fatigue, due to the effort required to memorize a number of different passwords for several services.
For a variety of reasons, users end up taking a dangerous shortcut: they reuse the same password (or small group of passwords) for everything. This approach is as secure as the weakest site you signed up with 1, which generally means it’s very insecure. A better alternative, and the approach I take, is to use a secure password manager instead. At this point it would be very challenging for me to work on Mac OS X, without having 1Password installed.
The reason I mention 1Password is because it has advanced features that generate randomized, secure passwords when you sign-up for a new site. Having that tool at my disposal further highlights the shortcomings of most web forms in regards to handling passwords. In fact, I often find myself changing settings in the password generator, just to satisfy the arbitrary rules defined by each individual form.
In light of the aforementioned considerations, here are a few suggestions for login implementers:
- Don’t ever store my password in plain text. When I sign up, don’t send me my password in clear text. If I can see my password in your recovery email, your implementation is not secure. Always store an encrypted (salted) version of my password. If I forget my password, I expect a reset link in my inbox. Oh and it should be obvious, but just in case it’s not, never use a text input field for a password.
- On a similar note, don’t allow my password to be transmitted in plain text, or it becomes possible for unwanted eyes to intercept it. SSL is your friend.
- If you try to prevent remote, brute-force attacks by limiting the number of login attempts, do so with a large, sensible number (e.g., not 3 attempts maximum). Also, understand that speed is not a desirable trait for hashing algorithms in this context. For this reason, it’s a good idea to use bcrypt, which offers a much slower and harder to brute-force algorithm that enables you to choose how time consuming the hashing operation should be. This is particularly important, if a malicious user manages to obtain local access to your encrypted passwords. It’s one thing to process, say, 100,000 hashes per second, and an entirely different thing to process 7 of them. Login and registrations are rare enough not to warrant fast encryption algorithms.
- Show me what the length and characters requirements for a password are upfront.
- If you choose to ignore the suggestion above, at least make these requirements clear in the error message you are showing me. Far too many times I’ve seen errors like “The password you entered doesn’t meet our requirements”. So, what are your requirements?
- Don’t cap the password to 8, 12, or even 15 characters. People who use password managers, may want to store strings of 35 characters, and should be free to do so. With the current technology, even a password with far fewer characters is secure enough 2, however there is no good reason to impose arbitrary limits that are so restrictive. Accept up to 50 characters at least (which happens to be 1Password generator’s limit as well).
- Don’t impose limits on the type of characters that are permitted. If I want to use special characters, I should be able to do so. This further strengthens the security of your users’ passwords, so why not allow it? If you don’t do so because you can’t make your code immune to SQL Injections, you should not be implementing a login system in the first place.
- Don’t invent arcane rules for password validation. It’s ok to require special characters, but if I have to think hard about what password could fit your criteria, you stand to irritate your new users. Feel free to show me how secure my password is though. Doing so may aid newbies when it comes to choosing a stronger password.
- If both the password and the confirmation are automatically filled in by a browser add-on like 1Password, don’t prompt me with an error saying that I haven’t filled in my password or that my password doesn’t match (I’ve seen this far too many times). Instead, strive to have a more reliable detection mechanism in place.
- Don’t show me an error message about mismatched passwords as soon as I leave the password field to proceed with filling the confirmation field in.
The majority of sites don’t follow these seemingly obvious guidelines. As a result, I often catch myself wondering if the password I’m about to submit will go through or not. That’s actually what motivated me to write this short article. I’m certain that some may disagree with a few of my points, while others may want to add more. Please feel free to do so in the comment section below.
1 Your client itself could be compromised of course (think about keyloggers, for example).
2 Technically speaking, no password system is ever truly secure. But as far as login systems go, these rules should be a good compromise between the need for security and the desire to avoid unnecessary frustration on the part of your users.
Get more stuff like this
Subscribe to my mailing list to receive similar updates about programming.
Thank you for subscribing. Please check your email to confirm your subscription.
Something went wrong.
Thanks, Antonio, very nice recap of what should *not* be done, as much important as what should be.
i don’t get point 10. why is that bad?
Thomas, while it is only a minor issue, it’s an annoyance to the user. If I just entered my password, and I’m about to confirm it, I should not be prompted with an error message. Error messages should be reserved for situations when something out of the ordinary happens (that prevents the sign up process from going through).
@thomas – He’s saying don’t show the password mismatch error as soon as you tab out of the initial password entry box. Ideally, I think, this error should only be shown as early as tabbing out of the password confirmation box.
e.g.:
Instead of
Speaking of annoyances, WordPress filters out HTML-like tags in comments instead of escaping them!
Take two – e.g.:
(password entry) (tab) (password confirm) (tab) (first time password mismatch error may appear)
Instead of (password entry) (tab) (first time password mismatch error may appear) (…)
The worst is when I use my password manager to create an awesomely long password, the website accepts it, and THEN I CAN’T EFFING LOG IN WITH THE PASSWORD IT JUST ACCEPTED BECAUSE THE IDIOT DEVELOPER ISN’T ESCAPING CHARACTERS CORRECTLY. This happens more than it needs to, really.
Good one, Zach. I HATE when that happens.
Why are you saying that GMail got it wrong for a long time? GMail used to be non-SSL by default for the content, but the login has always been SSL, as far as I can tell.
Giovanni, I think you’re right. I removed my remark about Gmail.
Hi Antonio,
Great post! Thanks for showing folks some best (and worst!) practices 😉
Thanks for your support of 1Password!
Cindy Compton
AWS Customer Care
http://agile.ws/support
http://twitter.com/1Password
This is a very useful post!
As you say a lot of site use a bad policy to manage not only the password but, more in general, the user-site interaction. In often happens that the real control of field is done after having post it and the user must re-write some field (e.g. password). But returning to the topic, of course the use of an application like iPassword make the security issue less stressful… but as you noticed it could be difficult work in a different machine without the passwords of iPassword so… why not use a portable solution?
The hard part is trusting these programs as well. As a Windows user, how can I trust a downloadable password manager? How do I know it doesn’t have a keylogger or send off my details somewhere?
Trusting one program can be as dangerous as only using a single password.
Matt, this is why I only use a program that has a company I really trust behind it. Otherwise you could extend the same logic to your browser’s company or even your OS’ company. It’s also not hard to check for programs phoning home.
Is there any Windows-based programs you would recommend? This is a brilliant article by the way, thank you.
Matt, I would consider the open source Keepass.
SSL isn’t absolutely necessary. Let me explain:
Users still don’t understand what SSL is, so if an attacker were to gain control over the user’s ISP’s DNS server, they could redirect DNS to their own server and steal the user’s login credentials. This means that if you can avoid it, you really don’t want to send the password as it was typed over the wire.
The solution is to implement challenge-response authentication. This requires changes on the client side though, and this is how you’d do it.
On the server, you store an encrypted password. You encrypt rather than hash because you want to be able to decrypt it later. This is your pseudo clear text password (since it can be decrypted by someone who has the key).
Now when a user comes to your login page (or sends an auth request through a non-browser based client), you send along a challenge string. For the non-browser based client, this could be based on the username, or not. When the user enters his login credentials into the form, you hash it client-side either using javascript for a browser or whatever language you want for a non-browser client. You then send the username and the hash to the server. This can be sent in clear text, since simply having the hash is insufficient for a replay attack. The hash has to match the challenge that was sent, and that changes on every request.
Once the request gets to the server, you run the same hashing algorithm on the decrypted password using the same challenge string, and if they match, you allow the user through.
This has the added advantage of being harder to brute-force because an attacker has to do the hashing on the client-side for each request, and has to use a different challenge for each hash (so he can’t just pre-compute hashes).
On the server, you still have to manage your assymmetric keys on different boxes (reg uses one way, login uses the other way), but that’s not terribly hard, and it means that if someone were to get login access, they’d need to be able to log in to two boxes. It goes without saying that boxes that store auth info (or any private info) go into a vault secured with a physical lock to prevent someone (eg: a bad employee) from just making a disk copy.
Oh, and this is not far fetched NSA stuff. Most internet companies that store user personal data should be doing this.
When visitors sign up on one of my site, I email them their login information (username+password) before storing the hashed salt of their passwords in my database. Does that considered bad too? If yes, would you mind explaining why?
@andy: email is not secure
Some time ago I wrote a python library to work with the 1password “agilekeychain” format.
It is a good exemple of a decent secure manner of storing passwords using password deviation algorithm and strong encryption cyphers.
I you want to have a look : http://github.com/gwik/agilekeychain
I would add “Don’t force me to put numbers and symbols to my password – if I want to use a 40 chars password, made up of 4 words and spaces, I want to be free to do that (and no one will ever hack my account)!”.