Web Security: Fundamental Obligations to Protect Users, Part 1
Part 1: Passwords
In this day and age, when there are highly publicized reports of security lapses associated with user data around the web, there is no excuse for weak password security practices to continue. Web services which require users to submit personal information, email addresses, use passwords or passphrases to access accounts, etc., have an obligation to exercise best-practice fundamentals when designing their services. Mistakes happen, breaches will occur, but neglecting to at least implement best-practice fundamentals is not acceptable.
Recently, I have experienced several examples of very poor security design on various websites and it simply baffles me that businesses allow this sort of condition to persist in the wake of so much negative press. We’ve had examples of poor practices made very public and embarrassing at: RockYou, Gawker, Stratfor, eHarmony, LinkedIn, Sony, Yahoo! and more, and yet developers and business managers are allowing the weakest of practices to persist.
Here are some simple examples of basic do’s and don’ts, describing what should be minimum habits of design. This represents just a few of the lowest of low-hanging fruit. There must be a complete and comprehensive security policy throughout.
1. Registration and Logon must be over HTTPS, i.e. Transport Layer Security (TLS), SSL, etc.
No exceptions unless the site is just a personal project for sharing a semi-private blog among friends and family and you don’t really care if non-members access it. For websites which are for commerce or community this should not be an option. There are security holes when redirecting from HTTP to HTTPS (or including logon forms on non-secure pages), but that’s another post.
2. Don’t store users’ passwords in plain text. Argh!
This is a big one. There’s NO justification for this and yet mega-corp Sony did exactly this (according to reports) and bore significant abrasion to their rep and their pocketbook, with the issue affecting millions of account holders. In fact they had to close down the PlayStation Network for quite some time while they retooled. And Yahoo! was recently hacked in which nearly a half million passwords were exposed for this weak practice.
3. Don’t skip the salt!
Passwords should, at minimum, be hashed with a strong salt, e.g. 32byte/256bits (a random string, not simply the username). Append the salt prior to hashing the password (or even better, use bcrypt to manage passwords). The salted hash is to be stored and the salt is stored, but the password is not. And very importantly, salts should be globally unique to each user. This prevents “economical” brute-force cracking of the password database with the use of rainbow tables.
This is such a basic practice, yet LinkedIn recently was caught by this one. It was reported that they did hash passwords, but they did not use a salt. I was really surprised by this as it’s such a basic security practice. By not salting the hashes, it was a relatively trivial task to expose users’ passwords by comparing to output using rainbow tables. The real problem here and the rub against users is that too many people re-use passwords on numerous sites, so access to the passwords represents a security threat to accounts elsewhere. This is also a big reason to use unique passwords for each online account. Users bear a big responsibility to password security, too.
4. Don’t use MD5 (or SHA-1) to hash passwords.
The MD5 hashing algorithm has been around since 1991. It was considered safe for years, but it has been demonstrated to allow collisions which means it can create the same hash strings from two (or more) different input strings (passwords). Although rare, that’s not good. Also, MD5 is very fast, but speed is not what we want when it comes to password hashing. The user won’t notice if it takes few milliseconds or few hundred milliseconds to complete the logon, but that difference will add 100 fold overhead to the efforts to crack the passwords in a stolen database table.
SHA-2 (or better) is now considered the reasonable minimum, but it, too, is very fast, so best practice should include additional iterations to drag out the process by a few hundred milliseconds. By repeating the hashing process many times, the latency is increased, and in this case that’s desirable. The practice of hashing a password multiple times is often called “key stretching”.
5. Don’t email users’ passwords to them in plain text!
Duh! Email is not secure and yet it is very common practice to email forgotten passwords to users instead of requiring a reset. Of course, if you’ve properly followed number 2 above, you’ll not be able to email a user’s password to them.
I recently purchased a jacket from an online adventure gear store. When I setup my account to check-out I was immediately emailed my login credentials, including username and password… in plain text! ARGH! I immediately logged-on to change my password (for which I did not receive an email, thankfully) and then e-mailed the company. I explained the security issue and expressed concern about the security of my credit card information as well. I received no reply and therefore will not be doing any business there in the future.
The following week we purchased an app from the Apple App Store (for $8) to help track a medical condition for my daughter. When she registered on their site so that the data on the iPhone would sync with the web application she was sent her logon credentials by email… in plain text! I wrote the developer and received no reply. Nice work guys. You can develop an app in Objective C; you can sell if for more than many other apps; your app syncs with an online Web application; but you can’t or won’t implement the most basic of procedures to protect your users?!?
Unfortunately, my daughter re-used a password she used elsewhere (bank account) so she had to change both. She was wrong to do so, but she’s not a web developer – and now she really knows better.
This very poor practice of emailing passwords in plain text is not rare, but it should be. There is no excuse for these lazy practices. In fact there are now “naming and shaming” websites where frustrated developers and users can expose websites which are using this poor practice. I’ve not posted any offenders to them, but I’ve been tempted. Plain Text Offenders is one example.
This is all too common even among supposedly “top-flight” web services. To my surprise, the first time I needed to help a colleague recover his password to access our projects on 37signals’ Basecamp, the password was sent via email in plain text. The hacker community brought this poor practice to the developers’ attention and posted publicly about it, but it persisted for more than a year in this state. Unacceptable. 37signals did finally correct the problem, but there’s no way to know if passwords are properly stored as salted hashes. I do hope so.
So how does one recover a forgotten password if the Web service shouldn’t email it to the user? You don’t recover one, you reset it – and there are right ways and wrongs ways to do that, and I’ll post some thoughts on that in a later entry.
6. Log data of each login, including IP address, failed attempts, etc.
Log, log, log. If the Gawker team had been watching login logs, as well as account creation logs, they would have known of their breach sooner, and perhaps before they lost control of their code and users’ data.
7. Allow users to enter strong passwords upon registration.
Web services also need to provide registration forms which allow and require strong passphrases, including the use of special characters (like $, %, [, etc.) in addition to upper and lower case alphanumeric input. Passwords should be case-sensitive! Too many websites ignore case, or put poor limitations on password entry forms. Allow long passphrases, and don’t restrict special characters.
Now, having said all of this about the responsibility of the Web services, users also have a responsibility to use and protect strong passphrases when registering with the websites. And please, use unique passphrases on every website, so that when one site is compromised you don’t suffer troubles elsewhere. We should also change passwords periodically. I’ve not always been perfect about this, but now I’m trying to be better about it.
Security issues on the web are evolving, and breaches involving data theft are becoming more prevalent than in the past. By maintaining a vigilant attitude about security in web development we can minimize risk and the consequence of unauthorized access. Good security practices are not only important to protect the web service and its business, but is proper and responsible consideration of users.
Let me know if I skipped over anything regarding responsible treatment of users’ passwords, and please feel free to add to my rant and plea in the comments.