The False Sense of Database Security

by Szymon Lipiński

In many web sites, passwords are usually stored in a database. I think this is well known to anybody who ever created any web page with user accounts.

Storing passwords in plain text is considered harmful. The only reason that I find is when someone gets the access to the database, or has the database backup, the passwords are just in plain text, so everyone can read them.

Quite a nice solution to this problem is hashing the passwords. The database stores no plain text passwords, but the result of some hash function.

hashed_value = HASH_FUNCTION(password);

The hash function is a one way function. This means that it’s very easy to calculate the hash value and it’s very hard to make the opposite calculation.

In all kinds of tutorials and blog posts the mostly used hash function is, unfortunately still, md5(). It returns 128 bit hash value. It means that there are only 2^128 possible values… what is quite a huge number: 340,282,366,920,938,463,463,374,607,431,768,211,456. The md5 algorithm contains some flaws and currently is not so secure. In fact it never was meant to be secure.

Hash functions can be “decrypted” using for instance the rainbow tables. This is not normal decryption, as we could not get the original plain text password. This kind of decryption allows to find a password that gives the same hash value that we have.

This can be some other text, not the one that user entered. However when using a hash function, only the hashes are compared. So having another text, which gives the same hash value, should be enough to log into the system.

This problem was partly solved using a salt. The salt is a random text, which is added to the password, before calculating the hash value. So the function now looks like:

hashed_value = HASH_FUNCTION(password + salt);

There is no decryption of the password in the databases. Instead the password provided by the user is hashed using the same algorithm and the same salt. Then the hash value is compared to the values stored in the database. There are some collissions, so two different strings generate the same hash value, so there is a possibility that you can login to a system using other password than user provided.

I’d like to see hash functions and salts in all databases. Unfortunetaly it looks like the most common way of storing passwords is just plain text. Last time I forgot a password to some two huge ecommerce websites, I asked to remind me the password, and I got it in plain text. I an unecrypted email.

That’s All

That’s all, if talking about security of passwords in web applications. I’ve hardly ever found something more, usually there just the short list: use hash function, or use hash function with salt.

There is Much More (Usually Ignored)

Database dumps.

Database dumps are not a problem as there should be the encrypted passwords, not plain text. They shouldn’t also use a fast algorithm like md5, it’s too easy to use rainbow tables to decrypt the hashes.

Database Logs.

I think logs are something nobody secures. Assume we have hashes in a database function. Application just performs a query like:

INSERT INTO users (login, password) VALUES ('me', 'pass');

and there is a trigger for hashing the password. The password is not stored in the database in plain text. Another solution could be running a procedure which adds a user, and hashes the password:

EXECUTE add_user('me', 'pass');

Then we could check the password entered by a user for logging in, with simple:

EXECUTE check_password('me', 'my_pass_for_login');

Nice, but what will be stored in the database logs? If we want to log all queries, what is very useful sometimes, then all those passwords will be stored there with plain text.

Application logs.

Applications have there own logs. The logs are stored somewhere else than the database logs, and should be secured as well. If the application stores in the logs the whole http request, then there is stored the password.

Quitea nice solution to this problem exists in the Ruby on Rails framework. Having the application controller like this:

class ApplicationController < ActionController::Base
  # filter out password parameters from log files
  filter_parameter_logging :password

protects storing in the logs any HTTP parameter named “password”;

All the passwords can exist in the logs, even if you hash and salt your password in the database. I think that in the application that you write, everything is logged, passwords too.

One more question.

What is the sense of storing passwords in any secure way, with secure connection and so on, if after registering to a web site, I get an email with my login and password sent with plain text?