4

We are using Firebase Database Rules to secure our database. We also would like to add additional security by encrypting sensitive user information. Right now our encryption approach is:

Encrypting user data client side with a public key before the user writes it to the database Decrypting with the private key on the server before delivering the data to the user through a GET request

Our private key is a string hardcoded in the server code. We want to secure the private key using KMS’s encrypt/decrypt methods, and store only the encrypted private key in the code.

An encrypted private key will be stored in the server code, and it will be decrypted using KMS on runtime, this way the developers won’t have access to the private key.

However, we wasn’t sure if there could be a better approach using Cloud KMS. Can KMS be used for client side encryption and server side decryption together? Or what is the best practice to use KMS to enhance database encryption?

2 Answers2

2

Your question is a good example of why you should not implement encryption and data security unless you know what you are doing. Your implementation is severely flawed. Asking is a good first start, but there is a lot to cover.

Normally, you do not use Private/Public key pairs to encrypt data. Public-key cryptography is used to securely negotiate a symmetric encryption key. Public-key cryptography is also very expensive in CPU time compared to symmetric encryption.

Example. Why bother to encrypt the data at the user side, if you are going to decrypt it on the server before sending to the client?

Hardcoding the private key in the server code is a horrible practice. This almost guarantees that your key pair will be leaked.

Yes, using Cloud KMS will be a huge improvement for you. This will make security easier to implement and remove some of the management headaches for encryption. However, you will need to understand KMS and encryption best practices. Poorly designed security is very easy to break. Poorly designed security is very easy to lose track of rending data inaccessible.

In simple terms, you will want the following at a minimum:

  1. Encryption Key Management
  2. Key Rotation
  3. Encryption at Rest
  4. Encryption in Transit
  5. Separation of responsibilities (admins cannot decrypt data)

Unless there is a good design reason or compliance requirement, you should not be encrypting data at the client - the client should not be managing keys. The data should be transferred securely using an encrypted transport protocol. Your server should be controlling and managing encryption for the database. The database should be encrypting data at rest also.

I could go on and on and this is why there are large books written on this topic.

John Hanley
  • 74,467
  • 6
  • 95
  • 159
0

I think your plan sounds like a decent one. Yes, you can improve security by wrapping your private key with Cloud KMS; then, you could put the wrapped key into your source code or your application's configuration files, then when it starts up, unwrap to get the private key. This would let you mitigate the risk of having the key which can decrypt the database handled by your developers.

Another approach would be to not use local crypto: instead, you could call KMS to encrypt and decrypt data every time a row is written or retrieved. This might give you some benefits (the key isn't even known by your binary; you get rotation, etc., as a part of the KMS solution; and you can get logs of every key use), but would have some costs (you now depend on the KMS service for every request; latency of KMS requests may decrease performance; the request-per-access costs more money than just unwrapping on startup; and you depend on channel encryption to protect the user data as its sent to your service, since you'd now be encrypting service-side).

KMS now also has asymmetric crypto support (docs here) so you could combine the two: do public key encryption client-side then use the asymmetric KMS key to do decryption for each request. Pros & cons are similar to above, except that you can keep the same data exposure and client-side encryption that you currently have.

I agree with another answer that the security benefit of doing client-side encryption here isn't entirely clear since the service has the authority to decrypt; it's not clear that having it do the encryption as well would result in increased risk. But using public key as you describe doesn't clearly lead to increased risk (presuming you do it well and correctly, not a trivial matter).

Thanks for your question and for using Cloud KMS; please let us know if you have any further questions we can help with!

Tim Dierks
  • 2,168
  • 15
  • 28
  • Let me explain our use case better. The user writes sensitive data to database using firebase write. We don’t want this data to sit on the database unencrypted. This is why we encrypt on client before sending to the database and decrypt before delivering it to the user from the API. Can you please help us find the best practice for “keeping the data encrypted on the database”? Is encrypting the data on client before writing to the database completely unnecessary because the transit to Firebase is already encrypted? – Tamay Eser Uysal Nov 03 '18 at 16:20
  • I see. Encrypting in the client is certainly useful since you can write directly from the client without needing a server-side intermediary. All the data in transit is encrypted, and all Google data at rest is encrypted by default, but if you want the data at rest encrypted with your key, using KMS in some fashion is a good idea. I think your public-key plan is a reasonable one, but it does require you to implement the wrapping. – Tim Dierks Nov 04 '18 at 00:16