Hacker’s Perspective: Securing JSON Web Tokens
If you are a modern-day developer, you’re probably plenty familiar with JSON Web Tokens (JWT’s). They are stateless, immune to Cross-Site Request Forgery (CSRF), and perform their job efficiently when correctly implemented.
Unfortunately, they can also be vulnerable to malicious threat actors. Many penetration testers will decode the JWT, ensure nothing sensitive is passed in a value claim, then move on to other more central parts of your API or application.
This leaves an opportunity for threat actors to dig into your authentication/authorization mechanism and search for avenues of exploitation.
Why Does it Matter?
JSON Web Tokens are Base64 encoded tokens that control a user’s session to your API. The token is made up of three parts separated by dots: the header, payload, and signature.
The header contains the type of token and algorithm used.
The payload contains the claims, which are statements about the user’s identity and additional data.
The signature is created by taking the first two parts of the token and encoding them with a secret. This verifies the integrity of the token, and that the data within it is not changed along the way.
JSON Web Tokens are stateless, which means the server validates users based on the token structure alone. If a threat actor steals this token, they can pass it to the server and control the victim’s session. JWT’s are immune to CSRF attacks because they are sent in the ‘Authorization’ request header, and therefore not automatically included in requests made by the browser (like cookies, for example). A threat actor would have to directly exfiltrate a token to access a user’s information.
What Are the Attack Vectors?
We can attack JWT’s using several known methods.
One attack vector we check for is the ‘None’ algorithm attack. This attack occurs when the JWT is created with the algorithm set to ‘None’ which allows anyone to generate a valid token. This is possible because the token does not contain a valid signature, meaning the server cannot verify if the payload has been modified.
Another potential attack vector is attempting to brute-force the secret key used to generate the signature. By compiling a list of common values (123456, password, etc) and using each one to generate a signature, we can make many attempts at guessing the correct secret value. If it is a weak value, there is a good chance it can be cracked.
These attacks and more are automated within the JSON Web Token Toolkit v2, also known as jwt_tool: https://github.com/ticarpi/jwt_tool. We use this toolkit on engagements that implement JWT’s to ensure their configuration is secure.
How Can You Fix It?
On our penetration testing engagements, we often see JWTs stored within the browser’s local Storage or session Storage. This is not safe! Any threat actor who finds Cross-Site Scripting within your application can easily pilfer these tokens with the following payload:
<script>alert(JSON.stringify(localStorage))</script>
Instead, opt to store your JWT’s inside an httpOnly cookie, so they are not accessible to client-side JavaScript.
Additionally, we recommend the following tips from:
https://www.bbva.com/en/json-web-tokens-jwt-how-to-use-them-safely/
Always sign the token
Use a strong secret when creating your signature
Set expiration date and unique ID
Set the issuer and audience
Don’t include sensitive data in the payload claims (they are base64 can be easily decoded)
Validate header claims
And last, ensure you have conducted a thorough penetration test on your application. Otherwise, you could be unknowingly putting your users and platform at risk of exploitation!