Structure of JWT
A JSON Web Token (JWT) is a compact, URL-safe token used for securely transmitting information between parties as a JSON object. A JWT consists of three parts: Header, Payload, and Signature, each base64-encoded and separated by dots (.).
-
Header: The header typically contains the type of token (JWT) and the signing algorithm being used (e.g., HMAC SHA256).
{"alg": "HS256","typ": "JWT"}
- There are three main types of algorithms that are used to calculate the signatures:
- HSxxx : HMAC using a secret key and SHA-xxx.
- RSxxx and PSxxx : Public key signature using RSA.
- ESxxx : Public key signature using ECDSA.
-
Payload: The payload holds the claims, which are statements about the entity (usually the user) and additional metadata. Claims can be registered (like sub, iat, exp), public, or private.
{"username": "administrator","is_admin": true,"iat": 1516239022,"exp": 1516242622}
-
Signature: The signature is created by taking the encoded header and payload, then signing it with a secret key (using the algorithm specified in the header). This ensures the token’s integrity, preventing tampering.
When a JWT is used, the recipient can verify the signature and decode the payload to extract the claims, which are used for authentication and authorization purposes.Each component is base64 encoded.
Tamper data without modifying anything
You can just tamper with the data leaving the signature as is and check if the server is checking the signature. Try to change your username to "admin" for example.
Origin
It's important to determine whether the token was generated server-side or client-side by examining the proxy's request history.
- Tokens first seen from the client side suggest the key might be exposed to client-side code, necessitating further investigation.
- Tokens originating server-side indicate a secure process.
Duration
Check if the token lasts more than 24h... maybe it never expires. If there is a "exp" filed, check if the server is correctly handling it.
Signature Verification
One of the most serious vulnerabilities encountered with JWTs is when the application fails to validate that the signature is correct.
Failed JWT Verifciation
When a developer uses a function such as the NodeJS jwt.decode() function, which simply decodes the body of the JWT, rather than jwt.verify(), which verifies the signature before decoding the JWT. This can be easily tested for by modifying the body of the JWT without changing anything in the header or signature, submitting it in a request to see if the application accepts it.
None Algorithm
The JWT specification also defines a signature algorithm called none. As the name suggests, this means that there is no signature for the JWT, allowing it to be modified.This can be tested by modifying the signature algorithm (alg) in the JWT header to none, as shown in the example below:
{"alg": "none","typ": "JWT"}
RS256 To HS256
The algorithm HS256 uses the secret key to sign and verify each message. The algorithm RS256 uses the private key to sign the message and uses the public key for authentication. If you change the algorithm from RS256 to HS256, the back end code uses the public key as the secret key and then uses the HS256 algorithm to verify the signature.Then, using the public key and changing RS256 to HS256 we could create a valid signature.
Adding New Public Key Inside Header
An attacker embeds a new key in the header of the token and the server uses this new key to verify the signature (CVE-2018-0114).This can be done with the "JSON Web Tokens" Burp extension.
Weak HMAC Keys
If the JWT is signed using a HMAC-based algorithm (such as HS256), the security of the signature is entirely reliant on the strength of the secret key used in the HMAC.If the application is using off-the-shelf or open source software, the first step should be go investigate the code, and see whether there is default HMAC signing key that is used.If there isn't a default, then it may be possible to crack guess or brute-force they key. The simplest way to do this is to use the crackjwt.py ((https://github.com/Sjord/jwtcrack)) script, which simply requires the JWT and a dictionary file.
Kid Issues
An optional header claim known as kid is utilized for identifying a specific key, which becomes particularly vital in environments where multiple keys exist for token signature verification. This claim assists in selecting the appropriate key to verify a token's signature.
- Revealing Key through "kid" : When the kid claim is present in the header, it's advised to search the web directory for the corresponding file or its variations. For instance, if "kid":"key/12345" is specified, the files /key/12345 and /key/12345.pem should be searched for in the web root.
- OS Injection through "kid": A scenario where the kid parameter specifies a file path used within a command execution context could lead to Remote Code Execution (RCE) vulnerabilities. By injecting commands into the kid parameter, it's possible to expose private keys.
- SQL Injection via "kid": If the kid claim's content is employed to fetch a password from a database, an SQL injection could be facilitated by modifying the kid payload. An example payload that uses SQL injection to alter the JWT signing process includes:
non-existent-index' UNION SELECT 'ATTACKER';-- -
- This alteration forces the use of a known secret key, ATTACKER, for JWT signing.
- Path Traversal with "kid": The kid claim might also be exploited to navigate through the file system, potentially allowing the selection of an arbitrary file. It's feasible to test for connectivity or execute Server-Side Request Forgery (SSRF) attacks by altering the kid value to target specific files or services.
- Tampering with the JWT to change the kid value while retaining the original signature can be achieved using the -T flag in jwt_tool, as demonstrated below:
- https://github.com/ticarpi/jwt_tool
python3 jwt_tool.py <JWT> -I -hc kid -hv "../../dev/null" -S hs256 -p ""
Conclusion
In conclusion, while JWTs are a powerful tool for secure data transmission, they must be implemented with caution. Ensuring proper signature verification, using strong secret keys, and guarding against the various attack vectors described are crucial steps in securing JWTs and the applications that rely on them. By understanding and mitigating these risks, developers can better protect their systems from unauthorized access and data breaches.
Want to write a blog?
Unfold your thoughts and let your ideas take flight in the limitless realm of cyberspace. Whether you're a seasoned writer or just starting, our platform offers you the space to share your voice, connect with a creative community and explore new perspectives. Join us and make your mark!