12

I'm securing API calls to a REST service I'm building using API Keys. The plan is to:

  1. When we get a new client, generate an API Key (a UUID).
  2. Email the API key to them.
  3. They send the API key on every call to our service (over HTTPS). We will lookup the API Key in our database (either encrypting or hashing it first) and figure out the account the API key is for.

Eventually, we'll add user accounts and a portal for all this so clients can generate and deactivate API keys without us needing to be involved.

My question is on the last part. Should I hash or encrypt (or leave unecrypted?) the API keys before storing them in the database? I'm trying to understand the implications. I know that if I hash them, then I'm protecting against someone knowing all API keys if they get DB access. But what are the other things I should be thinking about? For example, are there performance reasons to do one over the other?

Anders
  • 64,406
  • 24
  • 178
  • 215
Daniel Hipke
  • 121
  • 1
  • 1
  • 3

2 Answers2

19

Yes, you should absolutely hash your API keys. In effect, they are your passwords and should be treated as such. And note that's hashed - not encrypted. You never need to decrypt the API keys, hence you should not be able to.

As saghaulor says, you need to make sure you use a version 4 UUID (a random one, that is) and that you use a cryptographically secure source of randomness when generating them. Since a correctly generated UUID contains 122 bits of entropy you need not worrie about salting or using a slow hash function like bcrypt. A single round of SHA-256 would be enough.

A problematic part of your design is that you are giving users "passwords" that are delivered by mail and that they can not change. That may not be good enough for security concious users. Perhaps the portal you mention will solve this problem.

Anders
  • 64,406
  • 24
  • 178
  • 215
  • 1
    I realize this is an old question, but how would they implement that portal safely? The only alternative I can think of would be displaying the API key for X minutes after creation, to allow the user to copy it somewhere safe. Otherwise they would have to persist it as plain text anyway, unless they also encrypted it. Correct? – s.m. Nov 15 '19 at 13:47
  • 1
    @s.m. Yes. Correct. – Anders Nov 15 '19 at 14:14
  • 1
    Oh wow, you replied! Thank you very much, very kind of you :) – s.m. Nov 15 '19 at 14:16
5

1) Make sure you're using a secure random generator to generate your UUID.

2) Do not email the API key. Email has no guarantee of secure transport, which is to say, you're likely sending the key in the clear.

3) How you implement the authentication mechanism will affect how you can store the API key.

If you're going to use the API key as a primary key, then you cannot hash or encrypt it as searching is effectively impossible if you hashed or encrypted correctly.

If what you provide the user is a combination of primary key and API key, you can then securely store the API key. Since the key is effectively a password, hashing should be sufficient and is recommended.

Remember to use the algorithm correctly. Generally, hashing requires a salt for each record. There are different hashing algorithms. Some, like bcrypt and scrypt can add artificial latency to slow down brute forcing. This may or may not be suitable for your use case. Some algorithms are not recommended, such as MD5 and SHA1 as they have been proven to be insecure.

You could hash the key without salt and then you can do simple searches. This will not be as secure as hashing with salt, but the security of said approach may be sufficient for your purposes.

saghaulor
  • 504
  • 4
  • 6
  • So it sounds like if I have the API key as the primary key, I could hash without salt (making sure the hash doesn't collide with another key's hash) and store it. Then when I receive a request w/ API key, I hash it and look for a matching hash in the database. If I use a primary key and API key, then I can use a hash+salt because I can first lookup the salt by the primary key and compute the hash on the API key and see if they match. Am I understanding that correctly? Are there any recommended hashing algorithms that are fast and effective (considering this needs to be done on each request)? – Daniel Hipke Feb 23 '18 at 06:15
  • 1
    @DanielHipke If the API key is long enough, salting is not needed, because a brute-force attack cannot succeed anyway. Salting is useful for human-chosen passwords where only a small subset of the potential key space is actually used so that dictionary attacks become powerful. Salting makes dictionary attacks difficult. – Lutz Prechelt May 10 '21 at 11:51
  • Another overlooked part is, if you want the API KEY to be accessible in your users' dashboard every time, then hashing is out of the way, since you have to be able to show them the plain key. So encryption might be the only option in that case. – Shubham Kushwah Jul 12 '21 at 10:53