This article is a general introduction to JWT and it’s working, vulnerabilities, and tools for identification.
Introduction
JWT stands for “JSON Web Token.” It is a compact, self-contained way of representing information between two parties (Client and Server) in a secure and verifiable manner for the secure transmission of data in JSON format. They are encoded with base64 encoding.
They are especially common in the context of stateless authentication, like HTTP where the server doesn’t hold the client’s information so consequently a client has to verify himself by sending his/her information in every HTTP request along with other information. This is the reason why we see the browser sending its information through the cookie header in every request.
JWTs are used for authentication and authorization purposes in web applications and APIs. Here a question might arise for some people. How it is used for authorization? (we will come to this question later in the discussion)
As we know, a JSON Web Token (JWT) has three parts separated by a dot (“.”): Header, Payload, and Signature. These can be viewed after decoding base64 encoding.
Header: This is the part that includes the algorithm and type. The algorithm is used for the generation of signatures which might be symmetric, HS256 (HMAC with SHA-256), or asymmetric, RS256 (RSA Signature with SHA-256).
Payload: It includes the client and token data like issued date, expiry date, role, name, etc. as shown in the above pic.
Signature: It contains the signature which is used for verification of the user-supplied data.
How does it actually work?
First, when the user logs in with the username and password. This JWT token is sent back to the user as a response. The JWT token sent by the server is stored in local storage or cookie on the client side which is used for future communication.
How the JWT is calculated?
The server chooses the algorithm and type and puts them together in the header. Payload is put together by using the user-supplied data along with the time stamp for the creation of the token and expiry along with other information such as role, sub. After the creation of the Header and Payload, the server base64Url encodes the Header + dot (”.”) + base64Url encodes the payload. Then the server will take that portion and sign it with a specific secret key (which is only known to the server). After that server, The server uses a cryptographic hash-based algorithm i.e. HS256 on the portion (base64UrlEncode(header) + “.” +base64UrlEncode(payload), secret_key) to calculate the last signature part of the JWT token. Then all the parts are put together and separated by a dot (”.”).
Signature part can be represented like this: HMACSHA256(base64UrlEncode(header) + "." +base64UrlEncode(payload),secret_key)
I hope it clears up how jwt is calculated and sent back to the client. Now let’s see how future communication unfolds
When the client receives the jwt token, the token is stored in local storage or cache on the client side. Then the client uses the provided JWT in the HTTP request while requesting any page or resources. The server receives the request and once again calculates the signature using the algorithm with the header, payload, and the secret key to see if there has been any temper with the JWT token. If the client’s JWT signature matches the signature calculated by the server then the server successfully verifies the user and provides the requested resources.
In case an attacker tries to temper with the jwt token by changing it’s payload and creating a new signature he/she might require a secret key which is only known by the server. Hence creating a signature with a different secret key will result in a mismatch of the signature and the server forbids further communication.
Back to the question
How JWT is used for authorization?
The payload part may contain information about a user such as a privileges or role it is allowed to play. This way it can be used for Authorization.
Even if this system sounds robust it does have a number of vulnerabilities if not implemented correctly can be exploited by the threat actor. A couple of vulnerabilities to get started with JWT are:
Cracking of JWT token
Just imagine what can we do if we have the secret key of the server. Yes, as you have guessed as we already know the algorithm we can just create our own jwt token and create a signature, and will get verified by the server as well. You can take use of jwt-cracker, hashcat or john to crack the jwt token.
jwt-cracker: jwt-cracker -t eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.grxY_iKWUL7gU5ysP9i-x-kfZ9o1s8b-Xnq2PkmFUdI -a 1234567890
Hashcat: hashcat -a 0 -m 16500 jwt_token.txt wordlist
John: john jwt_token.txt wordlist
None algorithm
Now Imagine what happens if no algorithm is set. The server won’t have the appropriate algorithm to create the signature and assumes there is no algorithm so no signature is created. If we remove the signature part in the jwt token then it will pass through, helping us to impersonate any user or bypass the access control check.
Set the algorithm to none and change the value. Change the parameter that you want to be changed in the payload part. Then remove the signature from the JWT, but remember to leave the trailing dot (”.”) after the payload.
for eg: eyJraWQiOiI3NTgxZDViMi1iOTQ2LTQ4NTUtOGFiMC0xNDAyMTdkZTNmNzciLCJhbGciOiJub25lIn0.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6ImFkbWluaXN0cmF0b3IiLCJleHAiOjE2OTUwNjYzMDl9.
Algorithm confusion attacks
What happens if the server hasn’t taken into account the change of the jwt algorithm to any other algorithm? Algorithm confusion attacks, also called key confusion attacks, happen when a threat actor makes the server authenticate the signature of a JSON web token (JWT) using a different algorithm than the one intended by the website developers. If this issue is not dealt with correctly, it can allow the attacker to create legitimate JWTs with any values without having to know the server’s secret signing key.
You might be wondering, why we don’t need a secret key here.
Well, the developer didn’t take into account that a user can alter the algorithm to a different algorithm. So they are under the assumption that a user will use the default algorithm for eg RS256. Due to this flawed assumption, they may always pass a fixed public key to the method as follows:
publicKey = <public-key-of-server>;
token = request.getCookie("session");
verify(token, publicKey);
In this case, if the server receives a token signed using a symmetric algorithm like HS256, the library’s generic verify()
method will treat the public key as an HMAC secret. This means that an attacker could sign the token using HS256 and the public key, and the server will use the same public key to verify the signature. source
There are some tools that can aid in the testing of JWT
Burpsuite extension for JWT (JASON Web Token)
These mentioned tools can be used for scanning, altering, or cracking of secret code of JWT.