Gamasutra: The Art & Business of Making Gamesspacer
View All     RSS
September 2, 2014
arrowPress Releases
September 2, 2014
PR Newswire
View All
View All     Submit Event

If you enjoy reading this site, you might also want to check out these UBM Tech sites:

Protect your user's login details, please!
by Roger Haagensen on 04/28/11 03:52:00 am   Featured Blogs

The following blog post, unless otherwise noted, was written by a member of Gamasutra’s community.
The thoughts and opinions expressed are those of the writer and not Gamasutra or its parent company.


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.

Typical practices

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=" + + "&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=" + + "&password=" + hex_md5( + ":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!

  1.   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.
  2. 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.
  3. Make sure that the security answer(s) are hashed similar to securityanswerhash=md5("username:realm:securityanswer")
  4. Do not store the user login details with the credit card details ever, even if credit card details are encrypted.
  5. 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.
  6. 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.
  7. Do a internal review of your systems and think what info would be exposed and possibly exploited if the user login database was compromised.


Sony's Nightmare

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.

Closing words

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.

Related Jobs

Cloud Imperium Games
Cloud Imperium Games — Santa Monica, California, United States

Gameplay Programmer
Sony Computer Entertainment America LLC
Sony Computer Entertainment America LLC — Bend, Oregon, United States

Senior Graphics Programmer
Uken Games
Uken Games — Toronto, Ontario, Canada

Software Developer (Unity)
Sony Computer Entertainment America LLC
Sony Computer Entertainment America LLC — San Mateo, California, United States

Senior Software Engineer


Andrew Grapsas
profile image
This is all why I'm a huge advocate of OpenID! It's done once, right, and maintained.

Adam Bienias
profile image
Why it is maintained if done right ? ;)

Andrew Grapsas
profile image
Because part of "doing it right" is maintaining it, especially since information, protocols, and standards are constantly in-flux in the online world.

Joe Wreschnig
profile image
Of course, since you propose authenticating via a small hash, a longer passphrase would be useless from a security perspective. The actual authentication token is only 128 bits. It may still allow a more humane choice of secrets, though. You should also use a nonce, or you open yourself up to rainbow tables and replay attacks.

If you're recommending "rolling your own" rather than actually using HTTP authentication, you should really be recommending something better than MD5, as well.

The real rule of authentication is "don't do it yourself". It's sad that custom forms beat out digest authentication in practice.

Roger Haagensen
profile image
I'm assuming you are commenting on the article.

And to answer your questions, a longer passphrase despite using the same amount of bits when hashed is actually more secure.

If you are referring to MD5 in particular then yes the birthday paradox is higher with md5 than say sha1 or larger hashes.

But please remember that my advice is to ensure that the users "plaintext" password is kept secret. If the hash itself is obtained then they still would not be able to know the actual password, they might be lucky and make a matching (when hashed) password, but if something similar to how HTTP Digest Authentication does it, then the matching hash password would not work on any other site, nor even within the same site.

The benefit of md5("username:realm:password") or md5("username:realm:passwordhash")

is that even if two users have the exact same password (or passphrases that end up with the same hash if simple hashing is used), the stored digest hash would still be different, and add to that the realm and it's different for each site.

So there is no way for a attacker to know if the same password/phrase is used by the user on other services.

Also you mention nonce, that is only useful in the context of HTTP Digest Authentication,

you are probably thinking of salt, as a nonce changes each time and would not make sense for stored passwords. The user + realm actually is almost the same as a salt being added to the password/phrase.

As to rolling your own, yeah I'd advise against that unless you actually are recreating how HTTP Digest Authentication works. (non http client software might need to do that).

And as to MD5, that was only an example I stated such in the article as well. (you read it all right?)

One thing that is a shame is that HTTP Digest Authentication need to be modernized a bit both in UI as well as in other respects. Basic should be made to break now, and md5 should be minimum, and larger hashes like sha1 or bigger should be supported.

Remember, the article is an advise, I do hope that implementers do proper security auditing before making changes, or at the very least follow existing implementations to the letter and test thoroughly that they match the test samples of the standard. I assume you do so in your own software/services right?

Also the advantage of allowing 1 to 255 character passwords with UTF-8 characters is that dictionary and rainbow attacks are "almost" useless except for checking the most common passwords and phrases (there is never a fix for stupid password/phrase choices sadly),

is that brute force trial-and-error of the hash is the only way remaining,

and even md5 are still computationally expensive, sha1 even more so.

Personally I'd like to see 2048bit (256 bytes) hashes implemented by now, that would leave only guessable passwords and security holes the only ways left, and holes can be fixed.

Roger Haagensen
profile image
Here are some practical examples (feel free to test this yourself).

User 73388

passwordhash = md5("passtest") = "2f3bc18c0d3e6b1b8a445075535d26e9"

storedhash=md5("773388:gamasutra:2f3bc18c0d3e6b1b8a445075535d26e9") = "ac0135ed82ee5f7fcfbd1623c0d28f95"

User 73389 (which happens to have the same password, oops?!)

passwordhash = md5("passtest") = "2f3bc18c0d3e6b1b8a445075535d26e9"

storedhash=md5("773389:gamasutra:2f3bc18c0d3e6b1b8a445075535d26e9") = "74d6794d96a17db2f3ba753f175f9dee"

User 73388 on some other site (using the exact same password, outch?!)

passwordhash = md5("passtest") = "2f3bc18c0d3e6b1b8a445075535d26e9"

storedhash=md5("99944556:somesite:2f3bc18c0d3e6b1b8a445075535d26e9") = "2f432c35c6490033bed697d4063e68e8"

User 73388 on some other site (same password and due to coincidence same userid, whoops?!)

passwordhash = md5("passtest") = "2f3bc18c0d3e6b1b8a445075535d26e9"

md5("773388:somesite:2f3bc18c0d3e6b1b8a445075535d26e9") = "83441024554e314ff763bf3bce71e58c"

I kinda wish I had this example in my article, but hopefully some will read the comments and see this as well,

as these examples shows how effective the hash part of HTTP Digest Authentication actually is.

There is no way to see or know that all these 4 entries actually are the exact same password.

Joe Wreschnig
profile image
My mention of a nonce is to comment on how you say Gamasutra "should" be sending passwords. They shouldn't be sending passwords how they are as a plain hash, but nor should they be sending passwords by concatenating the realm as you suggest. They should be sending passwords with a nonced hash.

Rainbow attacks and dictionary attacks don't really care how long the passphrase is. If your authentication key is 128 bits, they need to be prepared to search 128 bits of space. Your 255 character passphrase will hash to the same value as some shorter one.

2048 bit hashes are ridiculous overkill and expensive to compute. 256 is more than enough. Actually, 128 is enough - I just wanted to correct the notion that a longer passphrase is somehow algorithmically more secure.

Storing passwords on the server should be done with bcrypt, period. Nothing else is really sensible - certainly not salted MD5s. Sending passwords should use hashes computed with nonces. You don't recommend either of those; your suggestions are bad.

Roger Haagensen
profile image
You are thinking about collisions. And those actually benefit the user.

Sure that could mean that "uid178:sonypsn.something:biffypass is a very long pass" hashes to the same as "xxxxx:zzzzzzz:5ddh5ED%" does.

Or if the crackers are lucky maybe "uid178:sonypsn.something:fh%¤%¤f"

But the pass fh%¤%¤f would only work there and not any other site.

A breach is a breach, and it doesn't matter what hashing is used once it's breached, the hash itself CAN be missused.

But the actual password still remains an unknown. Collisions/birthday paradox is actually a benefit for the user in this case.

And if you think 2048bit hashes is overkill/computing expensive then bcrypt is designed to be especially so. bcrypt has hardly been as vetted as sha1 or even md5 have yet. And if bcrypt is so good it should be used everywhere right?

You know as well as me that the industry is slow to adapt. At least using sha1 or sha-256 is a start.

And I never said Gamasutra should do it this or that way. I just used it as an example, in no way did I attack or belittle Gamasutra so please calm down.

And I never said that passwords should be sent without nonce, anywhere, please read what I actually write before throwing gasoline around please.

"HTTP Digest Authentication" does use nonce.

In fact I said "if properly implemented the passwordhash is used with a nonce" it's right there, please read what I actually write.

And if you really think this is bad, then please by all means tell everyone how it really should be as apparently you are a true expert in this matter right?

Unless you are actually a Cryptologist then people should put no more value on your words than mine.

I'm not a Cryptologist, but I am a seasoned programmer, I've seen the internet evolve since the start (and before) the WWW days, and I've dealt with my share of security and encryption issues and problems.

If you wish to disprove anything, then please actually dis-"prove" it.

Opinions are fine, but if you state them as fact then please reference them.

And I doubt the Wikipedia article on HTTP Digest Authentication is wrong.

All I mentioned in my article was an EXAMPLE, even my checklist states "use hashing solutions similar to HTTP Digest Authentication or better."

Do you notice the "or better" part? Or are you just ignoring parts of what I write so you can have something to argue about?

Kassim Adewale
profile image
Hi Roger,

Thanks for sharing this with us.

With security issues, sometimes you wonder what goes on in all those big corporations that you will assume they will have things done as common as primitive security SOP dictate. Don’t leave plain text around is a primitive security SOP.

Securing customer details is a complex work, especially if you are stepping on hacker’s toes. Sony should have done overhauling of any potential security breach that will further disgrace them from day one of the litigation between Sony and George Hotz. They should have allowed independent security experts to come in and review their processes.

There are some hackers out there that SHA384 or SHA512 protection won’t scare nor stop them. I propose a process where the cookie store the next expected salt with the login details:

loginUser.send("email=" + + "&password=" + hex_md5( + form.comp_name.value + form.password.value + cookie.next_salt.value));

Which means every log in render the last hash useless in the server database in case of attack. Only the PC that has the last cookie with the expected salt can gain entrance.

If the user failed to log in on the former PC, the old password expires and a new password is needed to kick-start a new cookie salt on the PC.

To add to your “The checklist everyone should read!” Roger:

8........ Have a counter on the database to observe login attempt and set limit to create a server alert to indicate attack.

9........ Have a password expire counter on the server databases to observe password duration.

10........ Remind user via email when their password has expired. Continue reminder until password is changed, caution on this to avoid spamming your user, you can allow user to select interval duration during password creation.

I hope Sony and all other organisation have learnt their lesson. I doubt it as we will soon read another big corporation mistake that goes negate the primitive security SOP.


Joe Wreschnig
profile image
Keeping the data in a local store is ridiculous. Cookies are unreliable and don't work for an increasingly common multi-device user. If password recovery becomes the norm (sadly it's already close) that's a step backwards in security.

You can get the same level of algorithmic security using nonces - you're basically just storing the next nonce an arbitrary time in advance, which makes it less secure overall.

But Roger's made it clear he's more interested in managing storage than authentication, in which case this doesn't help at all - you should just use bcrypt.

Kassim Adewale
profile image
Am not here to debate security, am just contributing, but nevertheless:

if you have a local data to get access to a server, it means your attacker needs two things. Please read HTML for Dummy, you don't know anything about cookies. I will assist you.

Cookie files are automatically lodged into the cookie file - the memory of your browser - and each one typically contains:

* The name of the server the cookie was sent from

* The lifetime of the cookie

* A value - usually a randomly generated unique number

The website server which sent the cookie uses this number to recognise you when you return to a site or browse from page to page. Only the server that sent a cookie can read, and therefore use, that cookie.

For your information, since you don't know, multi-device cookies are also possible.

I advocated for dynamic client + server based security not just server based that is ubiquitous. If Sony know the capacity of Ananymous group that attacked them, they will do more than what they are doing now that get breached.

profile image
I'm a huge advocate of services not tied to a console.

Jon W
profile image
Whilst it great to raise awareness around these issues, best practices are fairly well understood.

1) As regardings storing passwords (and I would say any Personally-Identifiable Information -- PII), "the minimum hash strength SHOULD be SHA-256 for the next few years."

Note that hashing is not encryption as I am sure you know Roger :) So bcrypt and SHA-512 would suffice for now.

If Sony have not done this (I don't know) then sadly it would appear another example of their naïveté in the realm of secure system design :(

2) All logins for applications storing any financial information (or IMO any PII) should certainly be done over HTTPS. All major players auth over HTTPS, and this is a considerable cost to them when they are certainly under attack constantly from script kiddies trying to brute-force accounts.

3) JavaScript-reliant websites are a personal bugbear of mine, personally I was disappointed to see this site relies on JS to log-in, and does other fruitless tasks like trying to regex valid email addresses, which is a non-trivial task. As the info it stores -- at least my details, cos I'm paranoid -- is low-risk, this doesn't bother me too much. So IMO the whole discussion about JavaScript obfuscation (and that's all it is) of the credentials over bare HTTP is moot.

I can see absolutely no reason for JS-reliance, but a valid business reason may exist -- like any decision of this nature, it's an exercise in risk analysis & cost-benefit analysis.

4) Nonces/Crumbs should be used on all sign-in forms to mitigate the risk of replay attacks and similar, and if you want to use JS obfuscation of login credentials, how about making a crumb with a very limited lifespan a part of that hash and tying it to a session ID on the back-end? (Note "Nonces" has unfortunate slang connotations in UK English and tends to be used mainly in the US.)

5) As for OpenID, usability, reliability and pain of implimentation means that sadly I would expect to see more and more sites dropping the use of it (37signals being one recent high-profile example).