The million-dollar question is: How do you store passwords safely?
User password security is one of the most critical aspects of developing a web application. However, writing a good authentication script isn’t easy. It’s so easy to get it wrong.
The best approach isn’t to store passwords, but that is not straightforward. Let’s think about how to make it as safe as possible.
How does it work?
How does it work in theory? It seems really simple. When you register, you choose your login and password. They are saved to the database.
Then when you log in, the server compares what you typed in the login box with the data from the database, and if it’s equal, it lets you in.
It’s pretty simple, isn’t it?
If you ever learned any server-client-related programming language (like PHP, for instance), you know that a simple authentication script is one of the basic lessons, and it sometimes looks like that, but I’ve got something to tell you – it’s wrong! Why?
It may seem like a safe solution, but this approach has its cons.
Think about this – What if you get hacked? What if your database gets hacked? I’ll help you. We’ll see something like this:

They hacked one password, the one to your DB, and now they have access to every account created in your service. “So what?”, you could say if your website has nothing to do with money or any other important data, but… take into account that it’s common for people to use the same password for different services. So the password used on your website could be valid (often with the same login and email!) for Facebook, YouTube… you name it!
When I started my adventure with PHP, tutorials on the authentication process using this approach were very popular.
If you think it has changed, you can take a quick shot at Google and search for examples. I can guarantee you that at least some of them will still teach you to store passwords like that. Don’t get fooled. If you want to make good scripts, always do wide research.
This approach seems naive now, but if you think no websites use this authentication method, you’re wrong. How to identify such services? By their ability to email you your password if you forget it.
That means it has to be stored in plain text, or it would be impossible to do. That’s why the only way to restore your password is often to set a new one. And don’t think that we are talking only about small personal websites.
We mean also websites managed by big corporations, shops, and so on. There is a nice service out there – Plain Text Offenders, which collects such websites.
But let’s get back to business. How can we strengthen our defense?
Encrypting
The first thought that comes to mind when you think about hiding passwords in plain text is to encrypt them. It’s a good idea, but it’s still not perfect. But before we start analyzing what’s wrong with this approach, let’s think about how to bring it to life.
So? How does it work?
Now user passwords get encrypted before they are stored in the database. When your user signs in, the script gets an encrypted password from the database, decrypts it, and then compares it with the password you typed. If they’re the same, the script lets you in.
It seems more secure, because now when somebody just reads out your database, he sees something like this:

Of course, if someone has access to your database, they can set up a new account with their password, then search their record in the database, copy their encrypted passwords, and paste them into every account they want.
Then, with that password, they can sign in to every account, even yours, the one with admin permissions! It’s bad, but at least they don’t have passwords of users, so they can’t use them on other websites.
It has got other cons, though. Encryption is a two-way function. It’s reversible, so you can always decrypt the string and get the original one if you have the key.
So it means that the attacker who gets access to your database can still get the original passwords. He only needs the key to decrypt them.
The other flaw comes from user incompetence. In theory, everyone knows passwords should be long, strong, unique, and hard to crack, but some people still love “123456″, “admin1″, and so on. If your website is small, it’s not so scary, but the more users you have, the more users could probably pick “123456″. I wonder If you already know what this means.
Encryption of the same password will always be the same, so you could end up with a database where encrypted passwords are repeated:

When an attacker sees something like this, it’s easy to conclude that repeated passwords must be popular. And it would be the truth!
Just another digression.
If you don’t use salt (it’s just a random sequence of bytes that is added to the password before being digested; I’ll tell you more about this in the next chapter) and the same passwords look the same after encryption, another thing that can reveal them is password hints. What do I mean?

Let’s analyze the previous table.
If we have the same password, every hint must fit. So if we store hints alongside the user password, the attacker gets as much help as many passwords there are.
If we could see only one, as in the standard procedure for restoring a password, it would be hard to guess. Is it a movie about the mafia? There are tons of them… But if we also know that Marlon Brando played there and Michael Corleone is one of the characters, then the difficulty is reduced to zero.
We already know that we’d like a safer system for our website. Could you believe that such a weak authentication system was used by, for instance, Adobe?
In 2013, hackers breached Adobe databases. Reports revealed that more than 130 million user accounts got leaked.
Hackers and… marketing companies quickly published the whole database online and made it a target. They received a great list of emails, and they knew a lot about this group of people just by the fact they were Adobe clients. In the article, we can read:
“The file holds Adobe IDs, email addresses, (encrypted) passwords, credit/debit card numbers, expiration dates, other PII (Personally Identifiable Information) and more.”
The worst thing here is encrypted passwords. We already know what the flaws are:
“The use of a symmetric cipher here, assuming we’re right, is an astonishing blunder, not least because it is both unnecessary and dangerous.
Anyone who computes, guesses, or acquires the decryption key immediately gets access to all the passwords in the database.” Paul Ducklin at Sophos [Naked Security]
So, is this a better approach? Yes. But it’s still not what we’re looking for.
Hashing
So encrypting seems quite a good idea, but the encryption key makes it really unsafe. How can we get rid of an encryption key? By making our encryption one-way only. If we encrypt and never decrypt, we don’t need an encryption key.
You can wonder – “What if one of my users loses a password? Can I send it to her/him?” – No, you can’t, but there are other solutions, like setting new passwords. But let’s get back to the topic.
Again, how does it work?

So what has changed? We NEVER decrypt, so we don’t need to worry about our encryption key. The same as before: we encrypt the password before storing it in the database.
What has changed is the sign-in step. This time, we don’t decrypt our password from the database (we don’t have any key, so we can’t do it anyway), instead, we encrypt the typed password in the same way, with the same algorithm as we had done it while registering. If both encrypted strings (typed password and password from DB) are the same, you’re in.
It’s not really complicated. But now we have a question: what password-hashing algorithm should we choose? The most popular ones are MD5, SHA-1, and SHA-2 (from the SHA family). They are really easy to use. But now the question arises. If they are popular, are they really safe? Well…
If you type the hashed code into Google and use a popular public algorithm, you’ll probably get a ton of results telling you what the encrypted value of that digest would be. Just try
“e00cf25ad42683b3df678c61f42c6bda” for example. The first result will already give you a decoded value “admin1″.
There are also things called rainbow tables, which really speed up the cracking of password hashes.
Rainbow tables are precomputed tables for reversing cryptographic hash functions. They’re mainly used to crack password hashes and recover plaintext passwords. Shortly, it’s a space/time trade-off.
You use less computer processing time and more storage. It’s faster than a brute-force attack calculating a hash on every attempt. It’s like a database of millions of precalculated hashes for specific passwords. Scary enough?
And the other flaw is again – common passwords. “123456″ and “123456″ still will give the same results to the database.
What do we have to do? We need to salt them.
Salting
Hashing and salting.
They have never invented anything more annoying than this, and it seems a really good approach for now. The salt is a random sequence of bytes added to the password before it’s digested. This makes the digest different from normal encryption. It protects us really well against rainbow tables/dictionary attacks.
There are two types of salting:
– fixed salt, a sequence of bytes used for every password. However, even if we keep our salt hidden, our system is still vulnerable to birthday attacks and doesn’t use the whole idea of salting. A birthday attack exploits the Birthday paradox. In short, it says that with a large number of user password digests, the probability of generating a password that collides with another digest in the table is higher than you’d expect. The more users you have, the higher the probability, and the easier it becomes for an attacker to crack your passwords.
– Variable salt is generated separately for each password. This makes the digest different for the same password each time. It’s safer, and it helps prevent the common password flaws I mentioned before.

The first option weakens when the attacker gets the fixed salt. He’s getting the key for all passwords then. There are a few ways an attacker can learn the salt. Brute-forcing his/her or somebody’s password is enough to get it.
The second option is much safer, but if the salt is random, we have to store it unencrypted alongside the hashed password in the database. Why? Because we will need it to regenerate the same algorithm we used for signing up while logging in. However, every password is different, so each one must be attacked separately.
The best option is to combine both. Then we generate a random string and compute it with a fixed salt. This way we’re much safer. The minimum recommended salt size is 8 bytes. At least 8 bytes should be random.
This way, every user password is completely random. This means you can’t pull the password back from it. Do you remember the Rainbow Tables flow? It won’t work now! Salt added to the password ruins it. It’s now a really long random string.
The common password flaw? It won’t work as well! The only thing the attacker can do is try every password he can find. A brute-force attack against a strong hashing algorithm with a long salt will take a lifetime to crack your password.
Oh! And one other thing – password guessing attempts limit. It’s a simple mechanism to implement, and it’s very important against brute-force attacks.
The iteration count
We now have a really safe algorithm, but there is another thing we can do.
The iteration count refers to the number of times the hashing function works on its own results. What do I mean? When you generate your salt and compute it with a password, you apply the hash function (SHA-1, MD5, or something else).
To make it safer, you can again apply the hash function on an already hashed result and then do it again and again… and again. It makes the final string even more complicated.
The minimum recommended number of iterations is 1,000, and it really should make you feel safer. It’s not really demanding work for the server, but for the attacker, increasing this complexity would make brute-force attacks even longer than they already are.
We’ve found what may be the best way to protect our users’ privacy. Not perfect, but at the moment, the best. Remember, however, that in security, in IT at all, everything is changing really fast. When designing your authentication system, look for the newest tricks and follow reputable people in the industry. And never let your authentication system get old!
External authentication
The best way not to worry about password security is not to store passwords at all. If you can, use Facebook login and Google sign-in on your websites so users can log in with their existing accounts.
Then you don’t have to worry about it yourself.
Passwords
We already know that weak passwords can harm not only individual users but the whole database. If we’re skillful enough, we can account for user incompetence and defend against it.
However, users themselves… they’re still easy targets with easy passwords. What should the perfect password be? I based my advice on the research of Matteo Dell’Amico, a researcher at Symantec Research, and Maurizio Filippone from the French research institute Eurecom.
The password must include uppercase and lowercase letters and at least one numeric character
The latest research shows that it doesn’t make them really stronger… but if it does even a little, don’t hesitate to use it.
Make the password as long as you can
It’s more effective. Make your password as long as possible. The longer it is, the harder it is to recover it.
Use symbols
The latest research shows it’s more effective than using only uppercase and lowercase letters.
Try to be the least predictable
Think of weird passwords; don’t use dictionary words.
Conclusion
The best way not to store passwords badly is not to store them at all.
Unfortunately, it’s not always possible. So if you really have to, pay attention to every detail. The password is the key to your service and sometimes to other people’s lives.
Remember that you have a duty to protect your users’ privacy. We’ve found what is probably the best way to protect it right now. But remember, the world is changing fast. Don’t let your incompetence expose user data.
You owe them privacy.
If you’re interested in learning how Jscrambler can protect your Web applications, request a demo.