Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Storing API keys on server

Tags:

security

api

I have a service where users each have an API key. I need to store the keys so that they can be used to validate API requests.

If I store the keys in plaintext in my database, I'm worried about the scenario of someone getting access to the db, grabbing all the plaintext api keys, then using them to impersonate others (there will likely be bigger problems if someone got access to the db, though).

This is similar to storing user passwords, where you just store the hash and validate using that - however most APIs let you view your API keys, which means they need to be stored in some recoverable way.

Is there a best practice for this?

like image 925
user3203425 Avatar asked Jun 21 '16 17:06

user3203425


1 Answers

The threat that someone gets the database and gets the keys means they can use the api keys to access the data in the database, which they already have, so no win there.

The threat that someone can access the database, get the passwords, means they can reuse those passwords on other web sites with the same user name because people tend to reuse their passwords.

Another reason having passwords in the clear or easily reversable is someone in your company could get a hold of the passwords, and start to do bad stuff acting as the user. Which IS a risk you might have if your API keys are in the clear.

Typically, HMAC is a solution for cryptographically computing a secure value from a single secret key, and some public value.

Have a look at HMAC. With HMAC, you can load a secret key into memory with the app (config file, read off of amazon KMS, typed in on app start, or however you want to get that secret key there).

In the database, store a token. Token = UUID() for example. The token should be unique to the user, the token could be versioned in case you need to regenerate, and the token could be random (like UUID). The token is not secret.

The API key is computed using the secret key (SK) and user token (UT) as follows:

API_SECRET = HMAC(SK, UT) 

Then distribute that API_KEY and API_SECRET to the user, and when the user tries to connect, you compute the API_SECRET:

  1. Get user record from database (you're probably already asking the user to provide their username)
  2. Compute the API_SECRET from the UT in the database:

    API_SECRET_DB = HMAC(SK, UT)

  3. Compare the computed API_SECRET_DB to the one provided in the request:

    if (API_SECRET_DB == API_SECRET_FROM_REQUEST){ //login user }

Bottom line, you only protect the Secret Key, and not every single credential.

like image 116
Jonathan Avatar answered Sep 23 '22 04:09

Jonathan