6

The database of my web app stores sensitive data. An attacker shouldn't have access to this data if he gains access to the database. That's why I want to encrypt this sensitive data in the database.

First I wanted to encrypt the users data with the user's username or password as key. The problem with this approach is that the user is able to change his username and password. In the case the user changes his user name the application can't decrypt the data that was encrypted with his old user name anymore. Also, the attacker has access to the user name of the user. Thus this wouldn't be a very secure solution.

The only other idea I have is to encrypt all user data with one global key. One drawback of this is that the whole system relies on one key. In this scenario I'm not able to change the key because of the incompatibility of the new key and the old data.

Do you have any better ideas on this problem?

Xander
  • 35,616
  • 27
  • 114
  • 141
Aaronmacaron
  • 63
  • 1
  • 4

3 Answers3

10

The generally accepted approach is similar to what AndrolGenhald suggested in an earlier answer but with some enhancements.

You can encrypt each user's data individually, using a key derived from their password. You do not, however, want to use the password directly as a key. It's a multi-step process, as follows.

1) You generate a random key, using a CSPRNGm, and use this random key to encrypt the user's data. You can create a new, different random key for each user. This is called the DEK, or data-encryption-key.

2) You take the user's password and run it through a PBKDF (such as PBKDF2, bcrypt, or scrypt) using a reasonably high work factor or number of iterations and a random salt to create a second key, the KEK or key-encryption-key. You then encrypt the DEK using the KEK, and store the encrypted DEK and the salt in the database.

Then, when the user logs in, you use their password and the salt from the database to regenerate the KEK, which you can use to decrypt the DEK, which you can use to decrypt the data.

Now, when the user changes their password, you no longer have to decrypt and re-encrypt all of their data, but simply use the new password (and a new salt) to generate a new KEK, and re-encypt the DEK using this new KEK.

Xander
  • 35,616
  • 27
  • 114
  • 141
  • 1
    I thought about this, but what if the user forgets their password? – MikeSchem Jul 28 '17 at 21:55
  • I guess it might be acceptable to have them re-enter the info if they forget their password. – MikeSchem Jul 28 '17 at 21:55
  • 2
    @MikeSchem They should have to re-enter their password to change it. If they forget their password, you have two (main) options. One, you keep a second copy of the DEK encrypted with a key you control, so you can decrypt their data for them, or two, they lose their data. This is the more painful, but more secure option. It's up to you and your potential users which model better fits your application. There are other variations, but these are the primary ones. – Xander Jul 28 '17 at 21:59
  • yea, I think this is one of the classic security vs convenience questions. Obviously if you use the second copy of the DEK, the you are essentially circumventing the whole process of using the user's password, but you do have the advantage of recover if (when) the user forgets their password. On the other had not recording the second copy of the DEK is more secure but less convenient on the user's behalf when they forget their password. – MikeSchem Jul 28 '17 at 22:05
0

You can either:

  1. Re-encrypt everything whenever a user changes their username or password
  2. Generate a random key for each user that you use to encrypt the data, then encrypt this key with the user's password (or username+password)

I wouldn't advise using just the username as a key, even if you do store the username encrypted (which seems a bit extreme), usernames generally aren't considered secret.

AndrolGenhald
  • 15,506
  • 5
  • 45
  • 50
0

If you want to encrypt the user's info, that is storred in a database I would advise you not store the key to decrypt the data in that same database. I would encrypt the contents with a secrete storred elsewhere with more strict access policies. That way the attacker needs to have access to both your key store and your database to get that data. This spreads out the attack surface.

MikeSchem
  • 2,311
  • 1
  • 13
  • 36
  • So this basically is a single global key to de- and encrypt all the sensitve data? – Aaronmacaron Jul 28 '17 at 21:43
  • well, you wouldn't necessarily need to have a single key. You could have a plain text file (or separate database for that matter) that contains a key per each user. The big idea is to store the key somewhere else than the encrypted data. Also make sure to HEAVILY lock down the key management system with permissions. – MikeSchem Jul 28 '17 at 21:53
  • Secrets really shouldn't be stored in source code. This will generally (and correctly) cause you to fail a security review. – Xander Jul 28 '17 at 22:01
  • @Xander yes, you're right. Really I meant a separate storage database with less access. I'll modify my answer. – MikeSchem Jul 28 '17 at 22:06