In recent years, JSON Web Tokens (JWTs) have become a popular method for managing user authentication and authorization in web applications. JWTs provide a way to transmit information between parties in a self-contained format. However, as with any security mechanism, there are risks associated with using JWTs that must be properly addressed to ensure the security of your application.
In this post, we will explore the basics of JWTs, including what they are and how they differ from cookies. Then we’ll look into some challenges developers face with JWTs. Finally, we will outline some of the best practices for implementing JWTs securely. By the end of this post, you should have a better understanding of how to properly secure your JWTs and ensure the integrity of your web application.
JWT stands for JSON Web Token, it is an open standard format for securely transmitting information between parties as a JSON object. JWTs consist of three parts separated by a period:
Let’s take a look at the following example of a JWT:
If we break this down into its parts, the first part (eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9) is the header and it decodes to:
The second part (eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTY3ODk2NDY4MCwiZXhwIjoxNjc4OTY4MjgwfQ) is the information being transmitted and it decodes to:
"name": "John Doe",
“iat” is the time the token was issued and “exp” is when the token would expire. These are some of the standard fields you would find in JWTs.
The last part (tQC7xwGRKg-p4bojB2mS7A-26_wNLwlrTeiInKH6LLc) is the signature.
JWTs are often used in authentication systems to generate tokens that can be passed between different systems or services to authenticate the user and provide access to resources. JWTs are self-contained, which means that all the information needed to validate the token is contained within the token itself. This makes them easy to use and implement, as well as secure since they are signed and can be verified by the receiving party.
Cookies are pieces of information that are stored on a user's computer by a web application typically used to store user preferences, session data, and other information. JWTs and cookies are both commonly used for client-side storage and transmission of data, but they are different in some ways.
|Security||Can be easily manipulated without detection if not properly secured.||Digitally signed and can be validated on the server. Manipulation can be detected.|
|Size||Limited to 4KB.||Can contain much more data, up to 8KB.|
|Dependency||Often used for session data on the server-side. The server needs to store the session map.||Contains all the necessary information in the token. Doesn’t need to store data on the server.|
|Storage Location||Browser cookie jar.||Local storage or client-side cookie.|
JWTs are typically stored on the client side, either in local storage or in a client-side cookie.
Client-side cookies are another way to store JWTs on the client side. To store a JWT in a cookie, the server can set a cookie with the token value and expiration date, and the client-side code can retrieve and send the cookie back to the server on subsequent requests.
While JWTs themselves are not inherently flawed, how they are implemented by developers can lead to security weaknesses in applications. There are a few common mistakes that developers can make when using JWTs. When you pair these mistakes with other vulnerabilities, they can cause significant damage to an application. For example:
Let’s look into some more challenges one would face while using JWTs.
The storage method chosen by developers can significantly impact the security of the JWTs and the application. Storing JWTs in memory is an effective approach because the data is only accessible within the browser's memory space. This means that if the browser is closed or reset, the JWT is lost. However, this approach may not be ideal for all applications.
On the other hand, session storage provides a more persistent storage solution for JWTs, as the data is stored within the user's session. However, session storage is still vulnerable to XSS attacks. An attacker can steal JWTs and gain unauthorized access to the application.
The best option is to store JWTs in a cookie with proper flags set, such as httponly, secure, and samesite. This is the only place where the JWT cannot be targeted by cross-site scripting (XSS) attacks.
Unlike cookies, which do not contain sensitive information, JWTs can contain a name and other sensitive information that should not be exposed to unauthorized parties. Developers need to be aware of what information they are storing in JWTs and ensure that it's information they can tolerate exposing to others.
JWTs are not meant to be modified, but they can be decoded to view the information inside them. Modifying a JWT is essentially an attack, and developers need to check if their application verifies the integrity of the encoded JWT beyond its initial issuing.
Credit card information, SINs, social security numbers, and other personally identifiable information should not be stored in JWTs. Although this is not as common anymore, it's still a good practice to follow through with education and awareness.
Developers don’t always remember to invalidate JWTs when users log out or change their passwords. This means that if a user logs out of an application, the JWT should become invalid, and if someone tries to use the same JWT, it should not work. But if developers do not invalidate the JWT, it can cause issues.
Imagine a library where a user logs into an app that uses JWTs. The next person comes in and uses the same computer without closing the browser. They can then go to the browser history, find the same site, and use the JWT key. This poses a risk of account takeover, especially in shared spaces.
Sometimes changing your password does not invalidate the old JWTs. If your account has been compromised, you would hope that the hacker loses access, but without proper invalidating of JWTs, they can still have access to your account through the old JWTs. All-in-all invalidating JWTs is a crucial implementation when using JWTs.
While JWTs themselves are not inherently insecure, developers need to understand the potential risks and vulnerabilities associated with their use. By following best practices for securing JWTs, such as the refresh token feature, developers can minimize the risk of security issues arising in their applications. Let’s look at some best practices to follow when using JWTs.
JSON Web Tokens (JWTs) can be a powerful tool when implemented securely. Here are some best practices for implementing JWTs:
By following these best practices, you can securely implement JWTs in your application and reduce the risk of JWT-related attacks.
Securing JWTs is a critical aspect of web application development. Despite their many benefits, JWTs can pose security risks if they are not properly implemented and secured. But good for us, developers can take steps to mitigate potential threats and ensure the security of their applications.
In this post, we went through some of the best practices to secure JWTs. By following these best practices, developers can ensure that their JWTs are properly secured, and their web applications remain safe from unauthorized access and potential attacks.
It is important to recognize that there is no one-size-fits-all approach to securing JWTs. Therefore, in addition to the above-mentioned practices, developers must consider their specific use case for JWT security, and take a proactive approach to secure their applications.