Protect PII in web app database by encrypting with public key paired with private key protected by users' own passwords?
Asked Answered
H

2

7

Goal:

I'd like to allow users to create questions and collect information from other users in a custom web app (PHP/MySQL in a shored hosting environment) and protect the data collected.

Background:

The default questions that all users answer are general enough that they can not be construed as personally identifiable information (PII), thus limiting my liability to protect it, but users who create their own questions will likely ask for PII which then becomes a liability.

What I would like to do is protect this information in such a way that if either the hosting account or the database were compromised (or both!), the PII would not be recoverable without a significant amount of work, and even then, only a small portion would theoretically be recoverable.

Proposed solution:

Assuming MySQL's built-in AES_ENCRYPT()/AES_DECRYPT() functions are used to encrypt the PII table, the passphrase would need to be stored in the hosting account, so if the hosting account were compromised, the data could easily be read.

Since the users' passwords are well protected (hashed with salt), I'm thinking of capturing their plaintext password during authentication, encrypting it, and storing it in the PHP session until the user logs out.

A public/private key combo will be created for each user with the private key being password protected with the user's password + salt.

Then, when PII data based on that user's custom questions are added to the DB, the user's public key would be used to encrypt the PII that they collected through the app. When the data is read (only when the user is logged in), the data would be unencrypted with the user's private key (which is unlocked with their password + salt).

The benefits I see are:

  1. in the worst case scenario, where servers completely compromised, app code is read to find encryption keys, PHP session files are decrypted to find user's passwords, then entries in the PII table associated with that user are decrypted, then only the PII collected from questions of currently logged-in users could be recovered. Any users not logged in would be safe.
  2. even the DBA or similar wouldn't be able to read the PII.

The drawbacks I see are:

  1. user passwords are stored in a recoverable form while they are logged in.
  2. users who forget their passwords would loose access to their data.
  3. each relatively small bit of data will take up much more space in the DB due to encryption.

My question: Is there a better way to do this?

Helenehelenka answered 30/8, 2011 at 4:16 Comment(4)
It's almost impossible to ensure protection as soon as your server is compromised. As soon as someone has access to the php-code he can easily modify the code to write all passwords (or keypairs) in a plaintext-file on login. As soon as the salt is known (or known how it is constructed), hash isn't save for protection.Linoel
Yes, for as long as the breach is undiscovered, passwords could be captured. The idea is containment and minimised leakage. At least some data would still be protected because, hopefully, the breach would be discovered fairly quickly and not all users would log in within that time frame.Helenehelenka
What exactly do you want to store in the PHP session? I don't see why you need an additional encryption key in memory if you only decrypt the private key on login.Sucre
need to store the password in the PHP session because the private key will be password protected and will need to be decrypted and used every time PII is pulled from the DB. No need to pull all PII and decrypt just because the user logged in. The user may only view a small subset of the PII stored during any given session.Helenehelenka
S
7

I see a number problems with this design from a security perspective. First of all passwords must never be encrypted, this is a vulnerability identified by CWE-257.

Further more MySQL's AES_ENCRYPT() is complete garbage for more than one reason. It uses EBC mode, and here is a good example of why this is crap:

Original Image:

enter image description here

EBC Mode (which is what mysql's AES_ENCRYPT() uses):

enter image description here

But if the database where compromised the attacker is going to defeat AES_ENCRYPT() by enabling the query log.

Using the user's password for encryption should be avoided, you should be using a crypgoraphic nonce. If you do use a password make sure you use a String2Key funciton. You must also use CBC or CMAC mode with a random iv. I don't really see how asymmetric cryptography can help. Asymmetric cryptography is very slow, memory intensive. They data that it protects is made less secure when the attacker controls the message because you can compare cipher text messages. This is why an random IV is important, and in the asymmetric world you don't have this level of protection.

Key Generation should look something like: $key=string2key($base_nonce.$salt.$user_password)

Make sure the output of your string2key function is the same size as your keyspace. So aes 128 needs a 128bit key. Each password should have its own $salt, and the $base is a cryptographic nonce stored in textfile. (An attacker would have to read this file before he can crack the key, if this value is large like 128 bits then its a moot point.) Each message needs its own $iv and this value must also be a cryptographic nonce (similar to a salt). I would generate the $salt,$iv and $base_nonce from /dev/urandom. The IV can be stored in plain text in a column in your database along with the cipher text.

From a legal standpoint even if you build a secure cryptogrpahic system you still have problems with insider threats and if the server is completely compromised, all of the data will still be compromised. This really isn't an engineering problem.

The best defense against a legal threat is a strong Terms and Conditions written by a skilled lawyer.

Sauternes answered 1/9, 2011 at 15:55 Comment(2)
+1 for this nice demonstration of EBC weaknesses and the advise regarding legal threats. I am however pretty sure that OP does not want to use AES_ENCRYPT and its counterpart, because he states in his post that "if the hosting account were compromised, the data could easily be read.", which he wants to prevent by using an asymmetric encryption/decryption scheme.Sucre
@Niklas yeah he wants to use asymmetric crypto which by all accounts is a worse idea.Sauternes
B
0

One concern I'd have is the following. The "any users not logged in would be safe" part is too optimistic. By protecting the private key with the user's password, you open yourself up to various password brute-forcing attacks. Not just for current sessions, but for all. One effective one is to simply enumerate the top 100 common passwords, say, and just try them out against all users. Attacker is bound to uncover some keys. (I'm assuming that you're either storing per-user random salt with the user record, which the attacker can see, or else that you have a secret salt that the attacker was able to obtain through the compromise.)

Beget answered 1/9, 2011 at 13:37 Comment(2)
Better ways to prevent password cracking are iterated hash algorithms (a brute-force attack will not be viable if you can only check 10 passwords/second) and especially forcing a strict password policy onto your users (minimum length, needs special chars/numbers/upper-/lowercase). Do not underestimate the power of modern GPU crackers, which can easily check hundreds of millions of weakly-hashed passwords per seconds (and this is only a single graphics card then).Sucre
Yes, the strict password policy is a big help. Without that, then even the 10 passwords/second is probably fast enough to uncover high-frequency passwords. Years ago I was the sysadmin for a system where all the passwords were stored as plaintext, and I definitely saw various passwords that kept coming up (users were known to be unique): "password", "p@ssword", "orange", "ilove[some_name]", "f*ckyou" and variants, "flower", 1337 versions of common words, etc. The key stretching helps too though.Beget

© 2022 - 2024 — McMap. All rights reserved.