In this article, we will cover:
For the sake of verbal communication, many developers have taken to pronouncing JWT as “jot” or “jawt”. Continuing that theme, I propose the pronunciation of JWS as “jaws” and JWE as “jawa.”
The JWT is formed by concatenating the header JSON and the payload JSON with a “.” and optionally appending the signature. The whole string is then base64 URL encoded.
A common use case is for instances where there is a need for HTTP request states to remain with the client. This is often the case with RESTful API implementations. A RESTful web service cannot keep a client state on the server and still strictly adhere to a stateless model, semantically speaking. Using a JWT allows the client to provide state information to the server for each request. This is especially helpful in secured RESTful web services that require some form of client authentication and authorization control.
Do not use a JWT when a session token will do. Generally speaking, session tokens are a well-established method of managing client access and they don’t bring any of the potential vulnerabilities mentioned below. A JWT excels in an environment where a stateless authentication method is warranted, single sign-on environments being a good example. However, there are other methods of transferring session data internally that can provide better security with comparable performance.
A JSON web signature (JWS) does not inherently provide security. A service’s security or vulnerability emerges from the implementation. The most common vulnerabilities created by a JWT/JWS implementation are easily avoided but not always obvious. Some of the more common vulnerabilities arise from implementations allowing the JWT header values to drive the validation of the JWT.
If the JWT processing function blindly adheres to the algorithm type declared in the header and the “alg” header is set to “none”, the JWT would be processed as valid without any of the protection that a signature provides. This allows attacking agents to set claim values in the JWT body to whatever suits their purposes. A hardened implementation of a processing function will only allow a strict set of header values and only validate a JWT that meets those restrictions. This is a well-known exploit at this point and most modern JWT libraries and helper functions should no longer be vulnerable to it.
Even when a JWT is signed, there are still some pitfalls to be aware of. There are three basic categories of signature algorithms in common use. The “none” algorithm, as discussed above, symmetric algorithms, and asymmetric algorithms. If a mix of different algorithms is allowed by the JWT/JWS consuming service, the processing function needs to guard against a common exploit used against asynchronous JWS implementations.
Consider an example of two encryption algorithms, hash-based message authentication code (HMAC) and Rivest-Shamir-Adleman (RSA). HMAC uses a shared secret key to form and validate the signature. RSA, an asymmetric algorithm, uses a private key to form the signature and a public key to validate the signature. A system that is using the RSA algorithm would be signing with the private key and validating with the public key. If a JWT was signed using the HMAC algorithm and the public RSA key as input, then the receiving system might be fooled into attempting to use the public RSA key it has as a way to validate the signature using the HMAC algorithm. This kind of attack works when the receiving system allows the JWT header to drive the token authentication. In this case, the attacker declared the public key of the asymmetric scheme to be the shared secret key of the symmetric signature scheme.
In order to prevent these vulnerabilities, we can follow some basic best practices when implementing JWTs.
As outlined above, giving control of authentication to the JWT can create a myriad of unexpected vulnerabilities.
A weak secret will allow attackers to generate valid tokens.
Protect tokens by adding a user context to tokens. A random string is provided during client authentication and kept in a hardened cookie for example.
Make sure that client tokens are being stored in a secure manner, i.e. hardened cookies.
Even with strong signature algorithms, it is important to limit the time for which a token is valid. This way, even if a JWT falls into the wrong hands, it has an expiration date that is predictable. If a token needs to be valid for an extended period of time, consider implementing methods for token revocation.
Issue the JWT with a very narrow scope of access. This way, even if it falls into the wrong hands it will only provide access to a reduced set of secured resources.
As with the previous point, enforce those limits on the receiving end. JWTs that make claims beyond the scope limit should be rejected regardless of their signature validity.
A careful observer might notice that a JWT or even a JWS makes no attempt to hide the data stored in the header or the payload. This is a very important factor to consider when considering the use of a JWT. No privileged information should be stored in a JWT.
With careful consideration, the use of a JWT can be a lightweight method for managing and securing resources. Evaluate if JWT is a good fit for the problem you are trying to solve. Review the implementation plan and pay special attention to the security implications.
Ned Imming is an employee at LogicMonitor.
Subscribe to our LogicBlog to stay updated on the latest developments from LogicMonitor and get notified about blog posts from our world-class team of IT experts and engineers, as well as our leadership team with in-depth knowledge and decades of collective experience in delivering a product IT professionals love.
LogicMonitor announced the appointment of Nitin Navare as Chief Technology Officer (CTO).
There are a few Agile certifications available to choose from, and in this article, we’ll discuss the best agile certifications currently available for IT professionals.
Join LogicMonitor Wednesday June 1st for Dinner @ Frankie & Johnnie's Steakhouse