Arstechnica recently ran an article on password cracking. A passerby might be struck with a little fear, considering this article might lead you to believe that, once the database is compromised, it is only a matter of a short time until your password is decrypted.
The article fails to mention, however, that the setup they used is about as close to ideal as possible for the crackers, or as close to naive as possible for the programmer who made the encryption layer in the first place. Encrypting passwords with MD5 is a grave mistake, MD5 being one of the weakest and fastest encryption algorithms available today. Secondly, the passwords were entirely unsalted. There already exist full rainbow tables and online lookup tables with nearly every possible MD5 value for unsalted alphanumeric strings. Theoretically anyone worth their salt (har) would be able to decrypt 100% of those passwords within a single day.
There are two sides to the password discussion, the programmer and the user. Each need to take their own precautions, but there’s a lot that can be done to combat the issue of databases being stolen, which seems to happen with alarming regularity these days.
Never use the same password twice
I’m guilty as anyone for establishing a “universal password”. Back about 10 years ago, having a good, strong, alphanumeric password was our best approach to password theory. Because we started requiring strange permutations like capital letters, numbers and symbols in passwords, it took a significant amount of time to completely memorize your complicated string. It was best to establish one complex password to be regularly reused.
10 years ago, having a good, strong, alphanumeric password was our best approach to password theory
However, this lead to an interesting phenomenon - cross-site (or service) account hijacking. As the industry switched over to email addresses being used as a username (not a terrible idea), and as passwords from less secured sites had their databases lifted, hackers would use the credentials from unsecured Site A to hack secure Site B. We saw this spring up extensively within the gaming industry, where a hijacked account could be turned into real world money.
…hackers would use the credentials from unsecured Site A to hack secure Site B
Players in an MMO would potentially use the same email (expected) and password (bad!) to sign up for both the game and, for example, their guild’s forum. Said forum’s server would be hacked, its database hijacked, and decrypted credentials sold. It was possible then to log into those user’s accounts, liquidate their characters, and resell that gold for real money. This has become a huge liability for online games as, while their own services were not hacked, a user logging in to find their characters liquidated would clearly rest the blame with the game itself. The thought wouldn’t even cross their minds that the hack had more to do with some remote forum or website.
Rather than establishing a universal password, its best to establish a universal password paradigm. This paradigm would cause the password itself to change from site to site.
I’ve heard of some people using the second or third letter in their password as the first letter in the name of the service they are logging into - that’s fine. But I think we can do better.
Why not devise a standard, easy to remember phrase which incorporates the name of the service you’re logging into? For example, you may have a phrase like, “ireallylike[servicename]” as your password, which would turn into “ireallylikefacebook” or “ireallylikeamazon”. Exceedingly simple to remember, a large number of characters to make password cracking rather difficult (the amount of time it takes to crack a password increases exponentially with each character), multiple words as to not be vulnerable to dictionary attacks, and becomes automatically different for each site/service. I’ve incorporated something like this into my password habits and I love it.
…devise a standard, easy to remember phrase which incorporates the name of the service you’re logging into
An interesting benefit is, on mobile devices, it actually makes typing these in quite a bit easier. No longer am I constantly toggling caps, numeric or symbol keyboards, and I’m actually more secure.
The downside are sites which have less-informed password requirements, requiring capitals, numbers and/or symbols to be present. I find these sites incredibly annoying, as they’re actually enforcing an anti-pattern for password management. Even worse are sites which restrict the password length to an arbitrarily low number. For those, I typically turn around and never sign up, as it demonstrates a very poor password storage policy in the backend.
Password storage best practices
When LinkedIn was famously compromised, it was revealed they used SHA1, no salt. Decrypting the database only was a matter of time. Without a salt, any standard SHA1 rainbow table was already well equipped to decrypt the passwords. What a disaster.
Salting your passwords is a good first step, but the best practice is to use a different salt for each user. By using the same salt for all users, a potential hacker could create a rainbow table using that single salt, and that table is good for your entire database. There would be an initial investment of the rainbow table’s creation, but it would only need to be done once. You want those rainbow tables to be as un-reusable as possible.
…use a different salt for each user.
Whenever I write a login script, my table will contain something similar to:
username | password | salt
The salt can be generated from anything; I usually go with a MD5 value of the timestamp of the password creation. Append their username if you want to ensure absolutely no one can have the same salt, incase two people register at the exact same microsecond (I’m not overly worried about that, personally). Some people may be initially surprised, “Exposing the salt! Gasp!” However, there’s realistically no problem with this. If you’re only using a single salt for a database, the concept of keeping it “secret” (and I quote “secret”, as any hack is going to inevitably reveal the salt, anyhow) seems to be important at face value. But when each user has their own, its secrecy is no longer critical for security.
And secondly, use bcrypt. The merits of bcrypt are fantastically outlined here. Simply put, bcrypt is designed from the ground up to be used with passwords in mind. It’s the best choice today for encrypting your passwords.
Password requirement prompts
If you enforce anything outside of length to your users, you’re doing them a tremendous disservice. XKCD has a fantastic comic on passwords. Simply requiring numbers or uppercase letters, honestly, does nothing to increase security. As a password cracker generating rainbow tables, of course you’re going to opt to use lowercase, uppercase, numbers and symbols. The english alphabet contains 26 characters, and you’re absolutely going to use uppercase letters as well, so you have a default starting point of running through 52 characters. Adding in numbers and symbols will add, optimistically, around 30 more characters. Whoopee. You could have a 6 character password full of numbers, uppercase characters in a completely random manner, and any password cracker will have it unlocked within minutes.
However, if users are allowed to simply have long passwords, the entropy increase is incredible. Each additional character adds an exponential amount of time to the cracking process. Getting up to 20 or even 40 characters produces passwords that would literally take decades to crack, accounting for Moore’s law. That being said, bcrypt does have a maximum limit of 55 characters. Considering we’re used to 6 or 8 character passwords, 55 seems more than abundant. Our earlier examples of “ireallylikeamazon”, for example, clock in at 17 characters - nearly triple that of the standard minimum of 6 character passwords, but not even close to the upper limit of 55.
Wrapping it all up
Protect yourself personally, and protect your users. Hacks happen to the best institutions. As a programmer, ensure that a hack is exceedingly difficult for crackers to benefit from, and as a user, limit potential hacks to only affecting a single site or service.