Secret Rotation for JWT Tokens

DZone's Guide to

Secret Rotation for JWT Tokens

Using some form of secret rotation when using web tokens to encrypt payloads is important to any security strategy. Read on for an example of how to implement this.

· Security Zone
Free Resource

Discover how to provide active runtime protection for your web applications from known and unknown vulnerabilities including Remote Code Execution Attacks.

When you are using JSON Web Tokens (JWTs), or any other token technology that requires you to sign or encrypt payload information, it is important to set an expiration date to the token, so if the token expires, you can either assume that this might be considered a security breach and you refuse any communication using this token, or you can decide to enable the token by updating it with a new expiry date.

But it is also important to use some kind of secret rotation algorithm, so the secret used to sign or encrypt a token is periodically updated, so if the secret is compromised, the tokens leaked by this key is less than it would be otherwise. Also, in this way, you are decreasing the probability of a secret being broken.

There are several strategies for implementing this, but in this post, I am going to explain how I implemented secret rotation in one project I developed some years ago to sign JWT tokens with an HMAC algorithm.

I am going to show you how to create a JWT token in Java.

try {

    Algorithm algorithm = Algorithm.HMAC256("secret");
    String token = JWT.create()
        .withIssuer("auth0")
        .sign(algorithm);

} catch (UnsupportedEncodingException exception){
    //UTF-8 encoding not supported
} catch (JWTCreationException exception){
    //Invalid Signing configuration / Couldn't convert Claims.
}

Notice that what you need to do here is to create an algorithm object, set an HMAC algorithm, and set a secret that is used to sign and verify the instance.

So what we need is to rotate this algorithm instance every X minutes, so that the probability of breaking the secret, and that the broken secret is still valid, becomes very low.

So how to rotate secrets? Well, with a really simple algorithm that everyone (even if you are not a crypto expert) can understand. Just using time.

So to generate the secret, you need a string. In the previous example, the was secret. This, of course, is not so secure, so the idea is to compose this secret string by a root (something we called the big bang part) + a shifted time part. In summary, the secret is <bigbang>+<timeInMilliseconds>

The big bang part has no mystery, it is just a static part, for example, my_super_secret.

The interesting part is the time part. Suppose you want to renew the secret every second. You only need to do this:

long t = System.currentTimeMillis();

System.out.println(t);
System.out.println((t/1000)*1000);

TimeUnit.MILLISECONDS.sleep(50);

t = System.currentTimeMillis();
System.out.println((t/1000)*1000);

I am just putting 0s to the milliseconds part, so if I run this I get something like:

1515091335543

1515091335500

1515091335500

Notice that although between the second and third print it has passed 50 milliseconds, the time part is exactly the same. And it will be the same during the same second.

Of course, this is an extreme example where the secret is changed every second but the idea is that you remove the part of the time that you want to ignore, and fill it with 0s. For this reason, first, you are dividing the time and then multiplying by the same number.

For example, suppose that you want to rotate the secret every 10 minutes. You just need to divide and multiply for 600000.

There are two problems with this approach that can be fixed, although one of them is not really a big issue.

The first one is that since you are truncating the time, if you want to change the secret every minute and, for example, the first calculation occurs in the middle of a minute, then for just this initial case, the rotation will occur after 30 seconds and not 1 minute. Not a big problem and in our project, we did nothing to fix it.

The second one is what's happening with tokens that were signed just before the secret rotation. They are still valid and you need to be able to verify them too, not with the new secret but with the previous one.

To fix this, what we did was to create a valid window, where the previous valid secret was also maintained. So when the system receives a token, it is verified with the current secret. If it passes, then we can do any other checks and work with it, if not, then the token is verified by the previous secret. If it passes, the token is recreated and signed with the new secret, and if not then obviously this token is invalid and must be refused.

To create the algorithm object for our JWT, you only need to do something like:

long currentTime = System.currentTimeMillis();

try {
  return Algorithm.HMAC256("my_big_bang" + (currentTime/60000)*60000);
} catch (UnsupportedEncodingException e) {
  throw new IllegalArgumentException(e);
}

What I really like about this solution is:

But, of course, there are some drawbacks:

So we have seen a really simple way of rotating secrets so you can keep your tokens safer. Of course, there are other ways of doing this. In this post, I just have explained how I did it in a monolith application we developed three years ago, and it worked really well.

We keep learning,

Alex.

Find out how Waratek’s award-winning application security platform can improve the security of your new and legacy applications and platforms with no false positives, code changes or slowing your application.

DOWNLOAD
Topics:
json web token ,jwt ,security ,authentication

Published at DZone with permission of Alex Soto, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.