2

I'm working on a web app and want to offer the users the option to "encrypt" their account. This wouldn't encrypt everything related to them in the database. Just certain critical fields.

I've already read D.W.s great response on the issue (https://security.stackexchange.com/a/16961/114330), and in spite of all that, I want to go through with it, because of some key differences:

First and foremost: None of the data I'm encrypting is critically important. This is a toy app, mostly for me to learn from and maybe put on a resume. There aren't any real users.

Secondly, I'm using existing frameworks and technologies. It's a Django app, so I've already got a bunch of protections and some sane defaults like csrf protection. I'm aware that's not magical pixie dust that's going to make my application secure, but "...I'm still learning, and doing the best I can."

With that out of the way, here's how I want to implement it:

  1. The user registers an account. During the registration, they are given the option for account encryption, and a separate password to use for the encrypted fields.
  2. Encrypted accounts have a bool encrypted, set to true. That is the only difference in accounts on the backend.
  3. When the user logs in, if encrypted=True, a prompt shows for them to type in their password, which is stored in client-side memory, and uses browser-side JS crypto (I know, I know...) to encrypt/decrypt the entries.

I want to make sure that nobody but the user can read their own entries, and this seems like a straightforward way of achieving that goal. But, as this is security, there's probably a million ways to do this wrong, and no perfect way of doing this right, so I'm very interested in the opinions of someone more knowledgeable than me, and would be really grateful if someone could point out potential vulnerabilities or areas where things can go wrong.

Alice
  • 33
  • 3

2 Answers2

3

Given that you say this is not a real application, I'll only comment on a couple of points here. The first is an implementation detail that you might have already considered, the second is more of a theoretical "is this worth while?" question.

1. Password changes.

It is generally considered good practice to require users to change their password every so often. If this password has been directly used to derive the key used to protect their data, then you're going to have a world of hurt ahead of you: you'll have to decrypt their stored data with the old key and then encrypt it with the new key. Yuck. Wasted machine cycles and a potential honey-pot for an attacker, since you have to go back to the plaintext to do this.

A better scheme would be to allocate the user a random key (their Data Encrypting Key or DEK) when they sign up, and encrypt that key with a key derived from their password (their Key Encrypting Key, or KEK). The DEK is used to encrypt the actual data, the KEK is used to protect the DEK, and is never stored. Then, when they change their password, they are just changing the KEK: the DEK does not change, and so the stored data does not need to be updated, other than the encrypted value of the DEK, which is now encrypted with the new KEK.

2. Is this a good idea?

Yes. Absolutely. Encrypting the actual data in a database protects the data against some threat vectors that less granular approaches don't cover. For example, neither an encrypted file system for storing the database tables nor database table encryption protects against a rogue database administrator with the ability to issue a select * from customers; query. If the data itself is protected and the keys are secure (an important consideration), all an attacker can get is the encrypted data.

That said, there are some issues to consider. For example, if you encrypt customers' SSNs in your database, will that impact your call center employees who routinely ask customers for their SSN in order to authenticate them? Plus, what happens when data from your system has to be exported in order to be sent to a business partner, who doesn't have access to your keys?

None of these issues are reasons not to implement security in your applications, but you should be aware that this is not a trivial undertaking.

Dave Mulligan
  • 501
  • 4
  • 7
  • I had considered password changing, but didn't come across an obvious solution to the problem. Having two keys is great. The issues you listed in your second point, I'd already considered, and decided encryption was worth the downsides. – Alice Jun 17 '16 at 17:21
1

Firstly, on HTTP there is no way to do this securely.
And when you include a TLS connection (a.k.a. HTTPS), why decrypt at the browser?
That sounds as possibly the worst place to do so.

If confidentiality is really that needed use proper encryption technologies like PGP/GPG and have the user decrypt / encrypt that on his/her/it machine. All you do is than store it.
Or if convenience is required encrypt/decrypt on the server, you always have to trust the server anyway so no real difference there.

I suggest you first re-read the page you discounted as a source and try to understand with a better degree why people say that encryption is not used in this way.

LvB
  • 8,217
  • 1
  • 26
  • 43
  • If the encryption is done client-side, what do you have to trust the server with other than reliably storing the data? This is absolutely something the user could do themselves with GPG before sending me the data, but I just want to automate that and have an easy UI for it, and using something like the Stanford Javascript Crypto Library seems the simplest way to do that. That way, all that's ever stored on my server is the data that the user encrypts/decrypts themselves, with their own encryption key, separate from their account password. I've intended to use TLS from the very start. – Alice Jun 14 '16 at 15:29
  • 1
    I'm not discounting the answer I read. I think it's very right. But I'm doing this _to learn_ about security, and in my mind, the best way to learn about security is to _attempt_ security, and then get feedback on my attempt. – Alice Jun 14 '16 at 15:46