JSON web tokens (JWTs) have become the preferred method for authentication by many organizations. They’re easy to implement, making them a popular choice for securing APIs and web applications. However, if not properly managed, JWTs can introduce security vulnerabilities, putting your systems at risk. You’ve probably used them yourself.
But have you implemented and handled them securely?
A blog post from Akamai highlighted several common security vulnerabilities associated with JWTs. It was a wake-up call to the potential risks of improperly managing your JWTs. In this blog post, I want to build on this, focusing on an additional vulnerability that is often overlooked: non-expiring JWTs. We’ll look at how this issue arises along with the associated security vulnerabilities. Then I’ll offer some guidance so you’ll know how to protect yourself from these security vulnerabilities.
Overview of Common JWT Vulnerabilities
Before we dive in, let’s briefly review the JWT vulnerabilities highlighted in the blog post I noted above. The six threats to JWTs that the writer mentioned were:
- Allowing the server to use a token without validation: This can happen when the server does not check the integrity of the token, making it easier for attackers to manipulate and exploit it. Attackers may also set the verification algorithm (alg) to none, attempting to manipulate the server into not validating the token at all.
- Using the same private key for different applications: This practice can compromise multiple applications if the key is exposed.
- Using a weak signing algorithm: Weak signing algorithms can be cracked more easily, leading to unauthorized access.
- Choosing a short and/or low-entropy private key: Keys that are too short or lack randomness are more susceptible to brute force attacks.
- Keeping sensitive data in a JWT’s payload: Sensitive information stored in the payload can be exposed if the token is intercepted.
- Confusing the keys: Mismanaging keys can lead to incorrect validation, allowing unauthorized access.
For detailed coverage on these vulnerabilities, check out the blog post. Moving on, let’s look at an additional vulnerability: the non-expiring JWT.
Additional Vulnerability: Non-Expiring JWTs
Let’s take a look at the following JWT, which is based on a real-world example that I encountered not too long ago:
This is a JWT used to authenticate and authorize a user’s access to an API. It’s signed with a secure secret to prevent spoofing. At first glance, it looks fine. But let’s look more closely at the payload:
{ |
When you look at that ttl claim, you probably think of time-to-live, because that’s what TTL typically stands for. So, this probably has to do with how long the JWT is valid. This must be the expiration time.
We can do some simple math here. Maybe 86,400,000 is the number of seconds, in which case the issuer intends this JWT to be valid for 1000 days. Or perhaps they mean milliseconds, in which case they intend this JWT to be valid for 1 day. That might make sense too.
But here’s the problem: The JWT spec says that expiration time is specified as exp, not ttl:
The “exp” (expiration time) claim identifies the expiration time on or after which the JWT MUST NOT be accepted for processing. The processing of the “exp” claim requires that the current date/time MUST be before the expiration date/time listed in the “exp” claim. Implementers MAY provide for some small leeway, usually no more than a few minutes, to account for clock skew. Its value MUST be a number containing a NumericDate value. Use of this claim is OPTIONAL. |
So then, we’ve got a couple problems here.
First, the issuer of this JWT is using ttl to specify expiration, but ttl is not a standard JWT claim. Most libraries designed to handle JWTs will not recognize ttl as an instruction related to token expiration. This will lead to compatibility issues, and the token will most likely be treated as non-expiring.
Second, the exp claim requires an actual timestamp of expiration, not a relative number of milliseconds (or seconds) from the issue time. This confusion likely stems from using ttl rather than exp. Nonetheless, the issuer needs to understand the expected format for the exp claim to ensure proper token expiration.
Whether you neglect to set the expiration time for a JWT or you set it incorrectly (as in our example), your JWT will be treated as non-expiring. And this presents a significant security flaw.
Without proper expiration, a JWT can be reused by attackersor leak beyond their intended lifespan,increasing the risk of unauthorized access. |
Mitigating JWT Security Vulnerabilities
Now that we’ve covered the potential security vulnerabilities, the follow-up question is: What should you do about it? Fortunately, mitigating this vulnerability is simple and straightforward!
Always use the exp claim. Set an expiration time on every token you generate. When you do so, make sure to use the standard exp claim with expected value format to ensure it conforms to JWT specifications and expires as intended.
Update applications and libraries. Ensure your application and any libraries you use are updated and adhere to the latest JWT standards. Regular updates help fix security vulnerabilities and improve compatibility.
That’s it. Follow these simple guidelines, and you’ll significantly reduce the risk of unauthorized access via a non-expiring JWT. This will improve the overall security of your JWT implementations.
Conclusion
Understanding and addressing JWT vulnerabilities is crucial for maintaining the security of your applications. In this post, we highlighted the risk of non-expiring tokens. By using the exp claim correctly and keeping your libraries updated, you can mitigate this risk effectively.
For further security solutions and best practices, explore the resources available in the Linode documentation. Linode offers comprehensive guides to help you remove security vulnerabilities from your applications.
Comments