Protect your users login details, please!
I am sure many are well aware of the PlayStation Network breach recently. No technical details about the breach have been given, so it's all speculation on that so far. What is not speculation is that the passwords and security questions was apparently stored as plaintext, and I will give a short advice on a Best Practice that I hope all developers that have a login system will evaluate. Plaintext and simple hashing of passwords should not be done.
Roger Hågensen considers himself an Absurdist and a Mentat, hence believing in Absurdism and Logic. Has done volunteer support in Anarchy Online for Funcom. Voicework for Caravel Games. Been a Internet Radio DJ with GridStream. Currently works as a Freelancer, Windows applications programmer, web site development, making music, writing, and just about anything computer related really. Runs the website EmSai where he writes a Journal and publishes his music, ideas, concepts, source code and various other projects. Has currently released 3 music albums.
In this example I'll assume that Userid/username and password is entered during login. (there are other solutions possible as well).
Many services still do the following:
The user and password is compared against the one stored in the database of the service,
if it matches you are logged in, and that's it.
Some of the smarter services do the following:
During account creation the password is hashed using md5 or more a newer hashing method, and stored in the database.
Later when logging in the user name/id is compared against the one in the database, and the password is hashed and compared against the hashed password stored earlier in the database.
This is a better solution, the password is not stored as plaintext. But there does exist md5 and sha dictionaries out there that can match a hash to common words found in dictionaries. These attacks are known as dictionary attacks or rainbow attacks.
What is the solution?
My advise is one based on HTTP Digest Authentication, sadly few actually use that or similar solutions.
During account creation the password is hashed the following way (md5 is just used as an example in this case)
passwordhash=md5("username:realm:password") then the passwordhash is stored in the database.
Later during a login the user enters as normal, the username and password, the server compares the username and then does md5("username:realm:password") and compares the result with the stored passwordhash.
If PSN had used this method (which by statements so far they seem not to have done) then the passwords would not be useful anywhere outside the PSN.
If only stored as plaintext or basic hashing then the password could be misused against other services the user might use.
It's one thing to have liability to your own users on your system, it's another to suddenly have so for your users on other services they also use.
HTTP Digest Authentication
HTTP Digest Authentication takes things a step further even, in addition to storing passwordhash=md5("username:realm:password") it also makes sure that you never send the password in plaintext across the net at all, and if properly implemented the passwordhash is used with a nonce (nonce is quickly explained a number or even a hash that is used only once), this is hashed with the passwordhash so you basically have passwordhash2=md5("passwordhash:nonce:someotherinfo") and passwodhash2 is sent across the net instead.
I would advocate HTTPS during any login, but a properly implemented HTTP Digest Authentication or comparable solution would even protect the users password over unsecured WiFi.
Considering how long HTTP Digest Authentication has been around I'm surprised it's not used everywhere as it really should be by now.
How about Gamasutra?
Well, I was pleasantly surprised to see that Gamasutra login actually does the following:
loginUser.send("email=" + form.email.value + "&password=" + hex_md5(form.password.value));
What this means is that it sends the password hashed with md5.
Although maybe after today they'll consider doing something similar to:
loginUser.send("email=" + form.email.value + "&password=" + hex_md5(form.email.value + ":gamasutra:" + form.password.value));
This protects against network sniffing (on say public WiFi networks), unlike what a simple hash of the password does currently.
As the login sends a hash to the server, I assume that the password is stored at least as a md5 hash in the gamasutra login database. And if lucky maybe they actually store it as passwordhash2=md5("username:realm:passwordhash") but I doubt that, but hopefully they'll consider that as well so that in the event that something like what happen to PSN happens to Gamasutra that simple hashed passwords will not be available but a digest hashing instead which is resistant to dictionary/rainbow attacks.
It would also have been nice with a optional HTTPS login, especially important for those on public WiFi's as the risk of Man-In-The-Middle attacks are very high there, and not only a digest hash can protect you then. (all data you send/receive can be falsified then)
The checklist everyone should read!
- Make sure that the password of users are not stored as plaintext or simple hash, use hashing solutions similar to HTTP Digest Authentication or better.
- Let users enter their own security questions, and if you are in the stone age and insist on a selectable list then still allow user entered questions as well please.
- Make sure that the security answer(s) are hashed similar to securityanswerhash=md5("username:realm:securityanswer")
- Do not store the user login details with the credit card details ever, even if credit card details are encrypted.
- Do not allow remote access login details (like passwords) or credit card details, these database entries should only be accessible from secure internal machines, and only by accounting or technical.
- Allow users to make any password they want, actually drop passwords, start using passphrases instead, allow 1 to 255 character passphrases and accept all UTF-8 characters, no more 6-8 character passwords please.
- Do a internal review of your systems and think what info would be exposed and possibly exploited if the user login database was compromised.
What happen to Sony with the PlayStation Network must truly be a PR nightmare for them, Sony is also hurt financially, stocks are affected, loss of customer and maybe worst of all, loss of trust in Sony as brand.
One might think that competitors like Microsoft might rub their hands together seeing a competitor hurt, but this is not the case, word is that MicroSoft is poking around their own services to double-check their own security "just in case".
I hope Sony will publish some more technical info so that everyone can learn from this expensive lesson, as not only Sony is hurting, but anyone selling a game on PSN, especially the independent developers, as well as users you can not play their online games and even some offline/single player games, related services or services tied to PSN is also affected.
But most importantly of all, users personal passwords is at risk, and we all know that the majority uses the same or very similar passwords all over the net. One can not expect a person to remember dozens of complicated passwords.
I hope everyone takes advantage and learn for this very costly and unfortunate situation that Sony is dealing with, and review the security of the login and password checking/storage for users.
My checklist may not be the ultimate solution, but it's certainly better than storing passwords and security questions as plaintext, or passwords with just basic hashing.
Think of your favorite online services/forums/blogs/social sites/net shops, check their FAQs, ask them if you need to. Show them the checklist.