In episode 120 of the TechSNAP podcast [skip 20 mins in], hosts Chris and Allan were discussing the breach of the Ubuntu Forums last month, when 1.82 million account details were estimated to have been at risk. According to Ars Technica, MD5 hashing was in place with a per-user salt. But whether you’ve got plaintext passwords, unsalted hashes, or single-iteration hashing, it’s time to upgrade. Chris and Allan discussed this issue, noting that when a user logs in, the web application has the plaintext password so that’s the opportunity to store the password using the new algorithm; users who haven’t logged in for a while will just have to wait. Of course, it doesn’t have to be this way, you can be a lot more proactive – and I’m sure Chris and Allan, who were just speaking off the cuff, would realise that too with a moment’s thought.
One solution is to use the current stored form as the input to the more secure algorithm, such as scrypt or a similar memory-intensive algorithm (not PBKDF2 if you’re going to do the job properly). Let’s say you currently store the MD5 hash of the user’s salt concatenated with the password. Rather than having to wait for every user to log in before password storage is improved globally, instead use the salted MD5 hash as the “passsword” input to scrypt, then overwrite the current hash value with scrypt’s output. (You did take a back-up, right?) That can be done for all users right now. When a user logs in, you’ll have to repeat your old hashing routine and feed its output into the more secure algorithm but this will add negligible processing time – which is of course why you’re upgrading!
While you’re making improvements, have a think about salts. While per-user salts are great, they tend to be stored right alongside the hash so, although rainbow tables should be rendered useless, the attacker can still try forward password attacks. Along with your salt, then, try a little pepper. For example, a simple improvement would be to add a system-wide salt that the web application knows without consulting the database. Then a SQL injection flaw won’t be enough to crack the hashes, providing the system-wide salt is suitably strong.
Another thing to consider is that if all the users’ juicy details are scattered in plaintext throughout tables within the same database, bear in mind that the attacker doesn’t need to crack the user’s hash to start exploiting their email address, date of birth, (dare I say) credit card number, etc. Cracking the hash is still attractive – it’s not just to get a nice GUI interface to the user’s details! – but this is where encryption of sensitive user data stored in the database can help.
For a clear introduction to memory-intensive algorithms try the Security Now podcast 388 (skip the news section and go to about 1hr:12min) or read the transcript (starting from “existing crypto technology”).