4

While working on a Java project using Spring-boot, Spring-security and JWT token, I need to provide access via API key and secret. After searching on Google for a while about key/secret generation, here is what I found:

  • For key generation, it seems a cryptographically-secured UUID without - would be a good choice.
  • For secret generation, I didn't find a clear suggestion yet. But it seems some other sites are using the HMAC-SHA512 algorithm for the secret, and store it as base64 string representation (padded out to 88 characters) of the key.

Here are some links describe API key & secret:

An example from a bitcoin site, that provides API key/secret access:

The questions are:

  • What algorithm is suitable for the secret?
  • Are the sha256 or sha512 algorithms a good choice? If yes, it would be helpful to have some suggestion on its generation.
schroeder
  • 123,438
  • 55
  • 284
  • 319
Eric
  • 151
  • 1
  • 1
  • 6
  • I am not sure I understand what you want to do. Could you try to define exactly what you mean with "key" and "secret"? E.g. what Java API are they going into? Or maybe its my lack of familiarity with Spring thats the problem here. – Anders Feb 23 '18 at 12:46
  • @Anders Hi, I added a `Update` part which describes the API key & secret, could you check that. In short, api key identify a user & an api, and api secret is like a RSA private key in some way, it's used to generate a signature for each request when the user request that specific api, so that to identify itself. – Eric Feb 23 '18 at 13:01

1 Answers1

2

I think you're confusing the security requirements for client IDs and secrets.

  • Client ID: Must be unique, better if unguessable. While they are typically not publicly advertised, they are not treated as carefully as secrets are.
  • Secrets: Must be unguessable and kept private. A potential leak of a secret is a security incident, requiring immediate revocation of the key.

What your client IDs look like is sort of a matter of taste. The examples in the oauth.com site you reference includes keys of varying sizes and formats. A random number is a fine choice. Something like (in pseudocode):

clientID = base64Encode(secureRandom(16)); // 16 bytes, 128 bits, 22 characters

In some situations you could use a non-secure random number, but there are situations where that may lead to predictability. So just stick with the secure random number generator - it's only a little slower and guaranteed to be safe.

The only way to generate a secret is with a secure random number generator:

secret = base64Encode(secureRandom(32)); // 32 bytes, 256 bits, 43 characters

Secrets should never be stored in clear-text. Encrypt them and store the encryption key somewhere secure.

You mentioned GUIDs, but even the random version 4 ones vary by implementation, some being secure and others not. So I'd just stay away from them. You also mentioned SHA256 and SHA512 hash algorithms. It is possible to use those in the calculation of a random number, but it's complex to get that right. Just stick with a secure random number generator and you'll be safe.

As you are already using Spring, RandomValueStringGenerator is probably a good choice for the implementation. Just create generators of the correct number of bytes. You can also look at the source code of that class for reference.

Neil Smithline
  • 14,621
  • 4
  • 38
  • 55
  • So, you mean the clientId don't need the secure random feature actually? And that's only needed by the secret ? I need to store the secret in database, you mean can't store the original base64 string? Can you tell more about the encryption of the secret before store it? – Eric Feb 23 '18 at 17:28
  • For the key generation, I have written a util using jdk's `UUID` class, it's also secure random. And, for the secret generation, I have written a util using jdk's `KeyGenerator` class to generate a SecretKey instance with `SHA512` or `SHA256` algorithm, it's also secure random, right? – Eric Feb 23 '18 at 17:39
  • 1
    I would make the client ID a secure random, though it is less critical than the secret. Having it being guessed is only a minor security problem, but why take a risk. I'm not certain of exactly the `KeyGenerator` implementation, but it is definitely a secure random. I might have just used SecureRandom directly, but this shouldn't be a problem. – Neil Smithline Feb 24 '18 at 03:22
  • 1
    Encryption of a secret is another question. There are many strategies for doing it, depending on your architecture. Search this site for `encrypting database fields`. [This question](https://security.stackexchange.com/questions/12332/where-to-store-a-server-side-encryption-key) discusses how to store the encryption key. What you want to protect against is the secrets being divulged if there's a successful SQL injection or other attack that gets the contents of your database. – Neil Smithline Feb 24 '18 at 03:29
  • it's always interesting to see the .NET people say "GUID" instead of "UUID" – BlueWizard Feb 24 '18 at 06:13
  • @NeilSmithline I need to use the original secret to validate the user's signature, so can't do a one-way encryption(e.g hashing). If I do a 2 way encryption, the attacker could also get the original secret from the encrypted secret, as long as he/she knows the algorithm which could be common, right? I have notices that some company use an extra `passphrase` field in addition to the api `key` and `secret`, and they only store a one-way hash of the `passphrase`, maybe that serves the encryption purpose you mentioned, I am not quite sure though. – Eric Feb 24 '18 at 08:30
  • Look at the question I pointed to you in my 2nd comment. – Neil Smithline Feb 24 '18 at 23:07
  • @BlueWizard - FYI, I'm a Linux/Unix and Java guy. Never did WINDOWS or .NET. Not sure where I picked up, GUID. – Neil Smithline Feb 24 '18 at 23:09
  • @neil-smithline nice. There's nothing wrong in saying GUID. It's just that the .NET people are basically the only ones (i know of) that say GUID. :-) – BlueWizard Feb 26 '18 at 07:22