3

Given scenario:
I have an application (NodeJS) running on Heroku, the database is RDS on Amazon and I use Auth0 for authentication. I don't have access to passwords of the users, some users use social media logins.

The problem:
The application has to store API keys from third-party platforms provided by the user and of course I want to prevent at all costs that anyone will ever have access to these data (with the keys, transactions ($) could be executed directly on other platforms!).

How do I encrypt the data when I don't have access to the user's password at any time?

The cases to secure I can think of:

  • Someone has access to my Heroku Account
  • Someone has access to my Auth0 Admin Account
  • Someone steals my database (e.g. by having access to the Heroku environment variable)

Can I securely save and access (while the user is logged in) the users API keys with my database?

It is okay for me, or even good, if I don't have access to the encrypted keys anytime. But I need them stored on my side in a persistent way. Its okay for me if the access is only possible when the user has an active session (by that I am giving up the possibility to perform any background tasks, but I do want to put security first and accept the negative impact on UX). I don't want to add another password for the API keys per user.

The solution can be on my end or using Auth0 or something like AWS Key Management Service, I have already done research but to me, it is still too blurry to say anything specific.

0

3 Answers 3

0

Protecting from someone getting the database contents is easy: Use a key (password) know to your application to encrypt the db records (a single key common to all users). That way, if someone stole just the db, the encrypted values would be without the key that is stored locally in the app node.

If the user would always be using the same browser, I would recommend to simply store the per-user "password" in a cookie¹ However, you may not be able to rely on that, and with such setup a user on a new browser would need to authenticate again producing new API keys (you will define if that's considered acceptable or not).

If the only thing you know is the identity, I think that you have no other course than using that for the encryption. I'm not familiar with the way Auth0 works, but it must be giving you some kind of user identifier (eg. an internal id or an email address) that is validated.

In that case you could eg. search the relevant database entry by looking for a record with the primary key being HMAC("foo", ), and decrypt the parameters with HMAC("bar", ), "foo" and "bar" being different secrets kept by your Heroku application.

Thus, only when knowing a user-id can the record be found and the secrets decrypted. This is not specially secure if someone got hold of both the database and the App², could try different identities, as emails are generally public (eg. I would begin by trying your email address). But still that requires testing users that could be there (from email lists gained from elsewhere, bruteforcing possible emails...).

¹ actually, localStorage / indexedDB would probably fit better.

² only one of them would not allow them to access any contents

1
  • One must assume an attacker will gain admin access, that is why it is not secure to encrypt passwords in a DB.
    – zaph
    Dec 28, 2018 at 16:04
0

You could ask the user for a "x"-digit "PIN" (for simplicity) or for another password and use this for encryption of the sensitive data each session... You can also append the PIN provided by the user to a general password to encrypt the data. For example, the user sends 5555 as his PIN. This gets appended to kH56ek7r91jfql giving as a result 5555kH56ek7r91jfql. Hackers might have access to the database and the second string of the crypt password but they need the user's PIN to decrypt it. Don't use ID or username because this can be easily reversed.

Edit: Don't save the users PIN, just use it to decrypt the API keys and hold them in memory while the session is active.

1
  • Never use the user's PIN (or password) to direct encrypt data. When the user changes it you will have to decrypt and re-encrypt everything. Use the PIN to encrypt a symmetric key, and that key will encrypt the data.
    – ThoriumBR
    yesterday
0

The one phrase that makes this exciting to me is:

"The application has to store API keys from third-party platforms"

I see two possibilities. Either:

  • While the user is logged in, you perform actions using these API keys on their behalf (this is the better situation for you), or

  • Whether the user is logged in or not, you perform actions using their API keys on their behalf (yikes).

In the first case, your job is a lot easier. You just decrypt when the user logs in, and you act using the API keys, and you discard them when the user logs or times out. You can use the user's identity combined with another key to encrypt the data (so that compromising the identifier + the database is possibly insufficient; they also need your key, presumably stored somewhere else with access control and auditing), and you don't need to store a password for the user.

I question a user that is sharing an API key with a vendor without establishing more / more verifiable identity information than that, but your customers are your customers, and it isn't absolutely crazypants. You might want to think about your plan for the case where you learn that one of your customers uses API keys that aren't technically theirs. (i.e. how do you point the upset person / org at the real culprit)

If you want to use their identifier as key material to encrypt data, you need to make sure you don't record (i.e. log) it anywhere. Obviously easiest is never log identifying info at all, but that might conflict with other goals.

You might start to address this challenge by logging a hash of their identifier, but that's risky because the identifiers are likely in consistent form, so might be guessable (i.e.guess-and-hash-to-check) One approach might be to ensure that there are collisions or another to make it v. expensive to generate the key (e.g. multiple iterations of hashing or otherwise manipulating the key material a la bcrypt) and the subsequent hash or other data that you log.

For the case where you use the API keys when the user isn't logged in, you're doomed if your goal is to avoid responsibility for securing them. You can't rely on anything meaningfully unique / known only to the user to do it because you have to access the keys while they aren't around.

Neat problem. Good luck with it. (I look forward to criticisms of this answer).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.