views:

70

answers:

3

We have a web app, which is written in Java, and storing data into a PostgreSQL database.

We'd like to encrypt a few fields in our database, as well as some uploaded documents. However, these all need to be 2-way encryption (ie, we need to be able to decrypt them), and decryption needs to be fairly fast.

However, we cannot come up with a "secure" method to actually encrypt/decrypt the data. Because this is a web-app, and there is no client, all of the encryption keys are going to be stored either on the web server (in plaintext, or our actual code), or the database server.

Any other ideas on how to actually make this at least moderately ... secure?

+2  A: 

No, there isn't. If your business layer must access the raw (unencrypted) data, then anyone who can hack your business layer (i.e. peek inside some keyword stored inside your application code or a file readable by your application) can also access the data. See also this related question.

Implementing some encription with the decoding key readable by the application only gives you a slight protection from casual data spying, and from some user roles or cases (example: a DBA who can read the DB but not the webapp; or someone who stole a dump of the DB, etc). But that's all.

leonbloy
@leonbloy: see my answer for an example of how yes, there is a way.
Borealid
@Borealid: yes, there are ways... impractical for most scenarios. A "password provided manually each time the application starts", for example, is hardly practical for a web app.
leonbloy
@leonbloy: If you leave the password in the application source (or configuration files), then an attacker would still need to physically obtain the token to compromise you. There's always a tradeoff between security and usability.
Borealid
A: 

AES is a well-established standard for symmetric encryption and support for it is built into the JDK, so I recommend you use that.

Now, you are quite correct that the key needs to be stored in such a way that your application can access it. However, rather than storing the key in your code or in a file, you can "split the secret up" into different physical locations to make it harder for an insider to beat your encryption. For example:

  1. At development time, generate a new key and "hard-code" it into your program. Call this Key A.

  2. At installation time, generate a second key. Call this Key B. Now encrypt Key B with Key A and store the encrypted version of it in the file system. Make the file readable only to the user under which the server runs.

  3. For each value you encrypt (say, each credit card number), generate a third key. Call this Key C. Use Key C to encrypt the value. Then encrypt Key C with Key B and store the encrypted version of it inside the database. (You could use a separate field in the same table.)

To decrypt, you would read the encrypted Key C from the database and the encrypted Key B from the file system. Use Key A to decrypt Key B, and Key B to decrypt Key C. Then use Key C to decrypt the value.

What does all this buy you? The idea is to spread parts of the secret around to several different locations, ideally controlled by different groups of people. Anyone who wants to crack an encrypted value will need access to all three items: the program code, the file, and the database. You could take this a step further and add more keys to the chain, but you get the idea.

Rob H
@Rob H: This is security by obscurity, since compromising the application compromises key C and bypasses the entire chain.
Borealid
Not sure what you mean by "compromising the application". If you mean viewing the source code, then that's not true because you can't decrypt Key C with just the source code.
Rob H
@Rob H: Controlling the application or accessing its memory, via code injection, root access to the server on which it is running, cold-boot attacks, side-channel disclosures, etc etc. Key C is decrypted while the application is running, and so is vulnerable.
Borealid
Well, certainly, but most of those threats exist with any approach including the one you propose in your own answer. ;-) My approach defends against a rogue developer or DBA who doesn't have access to the running web server, but might have access to the source code or database (or both). As for cold boot attacks, you could place Key B in an encrypted file system that's manually unlocked on boot or use a hardware token. But clearly, nothing offers complete protection from someone with full access to the running server and database.
Rob H
@Rob H: The difference is that, in the solution I propose, being able to passively read memory does not compromise the whole database. Instead, it only compromises the keys which are actively decrypted while the attacker is watching. That's the difference between having to tell a dozen users who logged in at the wrong time they were compromised and having to reissue every password in your whole system.
Borealid
I don't argue that it is a perfect solution. Indeed, there are no perfect solutions here. But it is more than "security through obscurity" because knowledge of how it's implemented doesn't mean you can break it, and it requires no special hardware.
Rob H
+1  A: 

You actually can make this a bit more secure.

If you use a smart token with a PKCS11 interface, generate a keypair on the token, and then secure access to the keypair with a password provided manually each time the application starts, then you can at any time in the future remove the ability to read the data by removing the token. In the event that fault tolerance is necessary, dual-encrypt using a pair of tokens.

The important principle here is that the private key is usable by the application, but not readable by the application. So, looking at the application source gets you nothing.

This solution will not stop someone who accesses your application while it is running from reading your data. But you couldn't stop that anyhow - they could read your data from memory before encryption.

This will, if correctly implemented, securely protect you against all forms of offline attack. The hacker cannot physically break into a good hardware token. The key cannot be extracted without knowing the password. The password cannot be guessed because the token has hardware limits on brute-force attacks. Thus, the only way to recover the data is to either steal the token and the password, or brute-force the data encryption key (which could be a 2048-bit RSA certificate).

Borealid