JWT is a new security token to transmit information between clients and servers securely. One of the main reasons why it is gaining traction is that it is easier and more cost-effective to implement than other auth tokens.
JSON Web Token Security is still not something that is commonly talked about as well. In this post, you will get an intro to JSON Web Token. You will also get a quick round-up of security issues you need to be aware of.
JSON Web Token (JWT) is an open standard that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret or public key.
When used in HTTP authorization headers, JWTs can authenticate users and authorize access to protected resources. JWTs can also be used in other application contexts, such as client-side form submissions or server-side API calls.
A JWT typically contains a header, payload, and signature, which are used to verify the token's authenticity and ensure that the information it contains has not been tampered with. The header usually consists of two parts: the type of the token, which is typically JWT, and the signing algorithm used, such as HMACSHA256. The payload typically contains claims, which are assertions about the subject, such as their name, email address, and so on. The signature is used to verify that the token has not been tampered with and is generated using the header and payload along with a secret key.
Security Risks Associated with JWT
JWTs are a common source of vulnerabilities in how they are implemented in applications and the underlying libraries. As these tokens are used for authorization and authentication, a vulnerability can easily result in various security risks.
A server could generate a token with the claim "logged in as administrator" and provide that to a client. The client could then use that token to prove it logged in as admin. The tokens can be signed by one party's private key (usually the server's) so that any party can subsequently verify that the token is legitimate. If the other party, by some suitable and trustworthy means, owns the corresponding public key, they, too, can verify the token's legitimacy.
How are JSON Web Tokens used?
JSON web tokens are primarily used for secure authentication and authorization between the client and the server. They are considered a secure way of information exchange between two services.
JWT for Authorization:
When a user makes a POST Request to a server, the server validates the credentials (username & password), and if they are authentic, it will return a JSON Web Token(JWT) in response, mainly a JSON object. Each subsequent incoming request will include the JWT in the request header or body, allowing the user to access the services and resources permitted with that token.
JWT for Information Exchange:
JWTs are an excellent way of transmitting data between client and server as these tokens are digitally signed, maintaining integrity.
Why do we use JSON Web tokens?
JSON Web tokens are used for a variety of reasons, some of them are:
- Securely transmitting information between client-server by using secure cryptographic algorithms
How Does a JWT Works?
A JWT Token is identified through a base64 encoded string separated by a dot (.). Before we dive into the structure of a JWT, let's take an example of a JWT.
As you can see, the above string is a JWT which consists of three parts, and a dot separates each part.
Note: You can use any Base64 decoder to decode the JWT token.
The header contains the type of token, JWT, and the algorithm used, HS256.
Payload is the part where all the information about the user is stored. It usually contains the user's ID (and other auth-related stuff) and the token issuance date.
In the above payload, the sub specifies the user ID to which JWT has been assigned, the name specifies the username, and it is the JSON object for the JWT issuance duration.
The last part of the JWT is the signature, which is a part that validates that the JWT is either correct or manipulated by anyone. By concatenating the Header and Payload, they are signed with the help of a secret key and the algorithm used to generate the JWTs.
The above signature indicated that the algorithm used is HMACSHA256, the header and payloads are both base64 URL encoded strings, and the secret key is a unique identifier that is also base64 encoded to sign the JWT.
Bypassing JSON Web Tokens:
Let's dive into the most exciting part of this blog post, bypassing JSON Web Tokens implementation in modern applications.
While JSON Web tokens provide secure communication between client servers, a poor implementation can result in critical vulnerabilities that can expose a severe risk.
There are many ways to bypass JWT implementation; some are listed below.
- None Algorithm
- Signature Validation
- Forged Signatures
- Brute Forcing Secret Keys
We will see the above methods and how to exploit these weaknesses individually. Whenever you figure out that the application is using JSON Web tokens, you should always look above techniques for bypassing it.
While testing the JWT, you should always check if the JWT allows no algorithm. Developers usually set the None algorithm during the development and UAT phase. Therefore the same configuration is deployed on production.
Now we have a web application in which we are currently logged in as regular users.
Once successfully logged in, you will be assigned a JSON Web token from the server.
You can add a burp extension (JSON Web Token) handy whenever you are testing the JWTs; you can add it directly through the bApp Store.
In the above request, you can see a JWT assigned to user "saad."
We can see that the supported algorithm used by the JSON Web token is RS256 which uses private and public key combinations for signing the tokens.
In the payload section, we can see the JSON object "name" and its value, which is our current logged-in user.
Now, to bypass the JWT through the None Algorithm, we have to make two changes in the token:
- In the header section, change the alg value RS256 to None (as shown in the below snapshot)
- In the Payload section of the JWT, change the user from "saad" to "admin."
Now you can send the new JSON Web Token to the server to see if the server validates the JWT or not.
Here you can see that we have successfully logged in as admin by bypassing the JWT through None Algorithm.
In this case, you should always check whether the server is validating the signature in the JSON Web Token.
Assume you're logged in as a regular user and want to escalate your privilege to the application administrator.
You logged in and captured the request through the burp proxy, as shown in the snapshot below.
In the above request, you can see in the Payload section that the current user is "saad."
Change the name to admin (as shown in the below snapshot). We must remove the signature part from our JSON Web token and send the request to the server.
Here is the final response from the server; you can see that we are logged in as the admin.
Forge the JWT Signature:
While testing any application, it's always worth finding the hidden directories that may expose sensitive information about your target; the same goes when you're testing an application that uses JSON Web Tokens for access control issues.
In this method, we will first fuzz through the directories to see if we can find any sensitive information (i.e., Cryptographic keys).
After fuzzing the target, luckily, we have a Public Key; let's login to the application and capture the request.
As we can see in the above request that the application uses JSON Web Tokens; we are logged in to the application.
You can copy the JWT and paste it on jwt.io to see the algorithm that it is using and what other JSON objects are being used in the payload.
Here you can see that the algorithm used in the JWT is RS256, which is asymmetric. Let's understand more about RS256.
"RS256 algorithm is an asymmetric algorithm that uses a private key to sign a JWT and a public key to verification that signature".
Since we have found the server's public key, we can use that key to sign the tokens.
First, we will change the alg RS256 to HS256 because HS256 uses the same key to generate and verify JSON Web tokens. We will also change our email to the administrator email.
As you can see in the above snapshot, we have changed the algorithm and our email address. In the next step, we have to create a signature, but before we do, let's see how the process will work.
- Go to the https://devglan.com/online-tools/hmac-sha256-online
- Paste the Header+Payload copied from the previous step (after changing the alg type and email)
- Paste the Public Key that we had previously found through directory fuzzing
- We will use SHA256 function to compute the hash and convert it into Base64
- Now we have the signature in Base64 encoding,
- We will convert the above signature into base64url encoding through (base64url.com)
Now we have our final signature, which we will add to our header and payload string; once it's done, we can send this newly crafted JSON Web token to the server to break into the administrator account.
Here you can see we are successfully logged in as the administrator.
Brute Forcing the JSON Web Token Key:
JSON Web tokens use secret keys, primarily stored in the application source code in some class (e.g., Java. Class, etc.). In some cases, the developers create weak secret keys, which can be brute forced through importing a wordlist and attack through John the Ripper or Hashcat.
JWT Secrets brute force list is available on GitHub, which can be found here:
You can clone the above list if you have git installed on your OS using the following command:
Now login to the target application, capture the request through the proxy, and analyze the JWT.
As you can see from the above screenshots, we are logged in as the user "wiener." We will copy the JWT from the request and brute force the key using Hashcat using the following command.
hashcat –a 0 –m 16500 <Path to the JWT Token> <Path to the JWT Secret List that we have downloaded previously from Github)
Run the above command to see if we can crack the JWT Secret Key.
We have found the secret key, "secret1," as shown in the snapshot above. Now, what next?
We will use this secret key to sign the token ourselves and reply to the request to the server to grant administrator access.
Now you can encode the secret key into its base64 encoded value; you may use the burp Decoder Tab to encode the secret key into its equivalent base64 string.
The secret key has now been encoded. Since we know that the algorithm used in the JWT is HS256 which is symmetric and uses the same key to sign and validate the JSON Web Token.
Now we will generate a new symmetric key; you can do that through the JWT Editor Key extension on Burp Suite. Change the username from wiener to admin and generate the JWT.
We will now sign the token through the key generated in the above snapshot. This will be done in JSON Web Token extension in the Burp suite.
Finally, now that we have a new JWT, what we will be going to do is to use any endpoint that only the administrator has the right to access (e.g., deleting the registered users in the application). In this case, we have an endpoint /admin which allows the administrator to delete the users.
We will craft a request to the subjected endpoint along with our new JWT to check if we can access the administrator dashboard.
We can see we are presented with the administrator dashboard.
While testing JWTs, always look for any sensitive endpoint which doesn't require proper authorization through JWT. Try to analyze the JSON Web Token carefully and play around with JSON objects in the JWT (e.g., timestamps, name, access type, signature verification, etc.).
Explore more with all you need to know about JWT, part 2.