views:

1768

answers:

6

Say each row in a table has data pertaining to one particular user. The user has a password to access the system.

How do I encrypt a column of data using InnoDB so that no one other than the user who's data it is can read the data ? I was thinking of something like using one of the MySQL encryption functions (say AES) with a key based on a hash calculated from the user's password.

Does any one have any pointers to how I could do this ? Am I on the right track ?

One of the answers below

The issue of modifying user's password involves re-encrypting the user key by means of the new password which is much more straight forward than re-encrypting the whole bunch of user's data that can be arbitrarily large. The user key remains the same accross the life of the user data in the system.

How does this help ? Say the password is pass1. And there are a bunch of records encrypted with a key generated from this. If the user now resets the password to pass2, I have no way of decrypting the data that was encrypted using pass1. In the case of a user forgetting the password entirely, all his encrypted data will be lost.

+2  A: 

I don't know if there is much sense in encrypting data with user's password hash, especially if you keep hash itself in the database. In that case anyone who can access the encrypted data can also access the password hash and decrypt the data.

Another approach would be to encrypt the data with the application-specific key salted with some user-specific data. However, then you face another problem: how to securely store the application key. To that question I do not know an easy answer, but keeping it in your source code is probably good enough if you fear that your database data can be compromised, but not the source code itself, e.g. if your database is stored off-site (think Amazon S3).

Salting the app key with the user's password helps if you keep only password's hash in the database, but can introduce another security flaw: you have to keep user's password in clear text in the applications session.

As for technical solution, it is quite simple and sample code is available. You could modify it as follows to encrypt the data with the application password salted with password hash:

INSERT INTO secure_table VALUES (
  1,
  AES_ENCRYPT(
    'plain text data',
    CONCAT(@application_password, @user_password))
);

In any case you would have to store your application password somewhere so I don't think that there is an easy approach that provides perfect security.

Another approach I can think of is to ask user for a short PIN which you could use as an encryption key. The PIN would not be stored in the database, but you would need to ask user for it every time you access their data.

And of course your have to think of is the feasibility of the encryption. You won't be able to index or to search it without decryption. It is probably required for a limited set of data (e.g. credit card number), but I wouldn't go to far with it.

Damir Zekić
A: 

I don't think that's the best approach, unless you're enforcing that users can never change their password, or you have a way to re-encrypt everything each time a user changes his/her password.

Jack Leow
A: 

You could store another key to encrypt/decrypt user specific data which could be generated when a new user is created. Let's call this new key user key. This user key should also be encrypted in database and the most direct approach would be to encrypt it by means of the user's password or any other data which cointained the password (such as the password and creation/modification time, etc.).

I would keep in user's session the decrypted user key to access user's data at any desired time within session.

The issue of modifying user's password involves re-encrypting the user key by means of the new password which is much more straight forward than re-encrypting the whole bunch of user's data that can be arbitrarily large. The user key remains the same accross the life of the user data in the system.

Of course this method can only be used if authentication is carried out by sending the actual user password to the server at logon, since database only desirably contains the hash of the password.

Fernando Miguélez
A: 

Say the password is pass1. And there are a bunch of records encrypted with a key generated from this. If the user now resets the password to pass2, I have no way of decrypting the data that was encrypted using pass1

The key would need to be encrypted in a reversable manner, so that it could be decrypted using pass1 and re-encrypted using pass2.

To summarize:

Stored in the database is: the one-way encrypted password (for password checking), the encryption key for other data, reversibly encrypted using the clear password (or at any rate, the password encrypted in some different manner than the way it is stored in the database), and the other data, reversibly encrypted using the clear encryption key.

Whenever you need the other data, you must have the clear (or differently encrypted than as stored in the database) password, read the encryption key, decrypt it with the password, and use that to decrypt the other data.

When a password is changed, the encryption key is decrypted using the old password, encrypted using the new password, and stored.

ysth
+1  A: 

To clarify one of the answers mentioned in the question: "user/app key" is a randomly generated private key, which is used to encrypt the data. The private key never changes (unless it's compromised). You encrypt and store the private key with a password. Since the private key is much smaller than the data, it's much cheaper to change the password: you simply decrypt the private key with the old password and re-encrypt it with the new password.

ididak
A: 

If you need to access the data without user interaction (for database migration for example), you won't have the key to decrypt.