JSON Web Token (JWT) Cheat Sheet for Java



{| style="padding: 0;margin:0;margin-top:10px;text-align:left;" |- Last revision (mm/dd/yy): // = Introduction =
 * valign="top" style="border-right: 1px dotted gray;padding-right:25px;" |

Many applications use JSON Web Tokens (JWT) to allow the client to indicate its identity for further exchange after authentication.

From https://jwt.io/introduction:

''JSON Web Token (JWT) is an open standard (RFC 7519) 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 (with the HMAC algorithm) or a public/private key pair using RSA.''

JSON Web Token is used to carry information related to the identity and characteristics (claims) of a client. This "container" is signed by the server in order to avoid that a client tamper it in order to change, for example, the identity or any characteristics (example: change the role from simple user to admin or change the client login).

This token is created during authentication (is provided in case of successful authentication) and is verified by the server before any processing. It is used by an application to allow a client to present a token representing his "identity card" (container with all information about him) to server and allow the server to verify the validity and integrity of the token in a secure way, all of this in a stateless and portable approach (portable in the way that client and server technologies can be different including also the transport channel even if HTTP is the most often used).

= Token structure =

Token structure example taken from https://jwt.io/#debugger:

'''[ Base64(HEADER) ]. [ Base64(PAYLOAD) ]. [ Base64(SIGNATURE) ]'''

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

Chunk 1: Header { "alg": "HS256", "typ": "JWT" }

Chunk 2: Payload { "sub": "1234567890", "name": "John Doe", "admin": true }

Chunk 3: Signature HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), KEY )

= Objective = This cheatsheet provides tips to prevent common security issues when using JSON Web Tokens (JWT) with Java.

The tips presented in this article are part of a Java project that was created to show the correct way to handle creation and validation of JSON Web Tokens. You can find the Java project here, it uses the official JWT library.

In the rest of the article, the term token refer to the JSON Web Tokens (JWT).

= Consideration about using JWT =

Even if a JWT token is "easy" to use and allow to expose services (mostly REST style) in a stateless way, it's not the solution that fits for all applications because it comes with some caveats, like for example the question of the storage of the token (tackled in this cheatsheet) and others...

If your application does not need to be fully stateless, you can consider using traditional session system provided by all web frameworks and follow the advice from the dedicated cheatsheet. However, for stateless applications, when well implemented, it's a good candidate.

= Issues =

Symptom
This attack, described here occur when a attacker alter the token and change the hashing algorithm to indicate, through, the none keyword, that the integrity of the token has already been verified. As explained in the link above some libraries treated tokens signed with the none algorithm as a valid token with a verified signature, so an attacker can alter the token claims and tkey will be trusted by the application.

How to prevent
First, use a JWT library that is not exposed to this vulnerability.

Last, during token validation, explicitly request that the expected algorithm was used.

Symptom
This attack occur when a token has been intercepted/stolen by a attacker and this one use it to gain access to the system using targeted user identity.

How to prevent
A way to protect is to add "user context" in the token. User context will be composed by the following information:


 * A random string that will be generated during the authentication phase and will be included into the token and also send to the client as an hardened cookie (flags: HttpOnly + Secure + SameSite + cookie prefix).
 * A SHA256 hash of the random string will be stored in the token (instead of the raw value) in order to prevent that any XSS issue allow the attacker to read the random string value and set the expected cookie.

IP address will not be used because there some situation in which IP address can change during the same session like for example when a user access an application through his mobile and he change of mobile operator during the exchange then he change legitimately (often) is IP address. Moreover, using IP address can potentially cause issue at European GDPR compliance level.

During token validation, if the received token do not contains the right context so, it is replayed and then it must be rejected.

Implementation example
Code to create the token after success authentication.

Code to validate the token.

Symptom
This problem is inerrant to JWT token because a token become only invalid when it expires. The user has no built-in feature to explicitly revoke the validity of an token. So, in case of steal, a user cannot revoke the token itself and then block the attacker.

How to prevent
A way to protect is to implement a token blacklist that will be used to mimic the "logout" feature that exists with traditional session system.

The blacklist will keep a digest (SHA-256 encoded in HEX) of the token with a revokation date, this, for a duration that must be superior to the duration validity of a issued token.

When the user want to "logout" then it call a dedicated service that will add the provided user token to the blacklist resulting in a immediate invalidation of the token for further usage in the application.

Blacklist storage
A database table with the following structure will used as central blacklist storage.

Token revocation management
Code in charge of adding a token to the blacklist and check if a token is revoked.

Symptom
This attack occur when a attacker access to a token (or a set of tokens) and extract information stored into it (JWT token information are base64 encoded at the basis) in order to obtains information about the system. Information can be for example the security roles, login format...

How to prevent
A way to protect, is to cipher the token using for example a symetric algorithm.

It's also important to protect the ciphered data against attack like Padding Oracle or any other attack using cryptanalysis.

In order to achieve all these goals, the algorithm AES-GCM can be used in conjunction with Additional Authentication Data (AAD) feature.

A database can be used to store the NONCE and the AAD associated to a token.

Note:

Here ciphering is added mainly to hide internal information but it's very important to remember that the first protection against tampering of the JWT token is the signature so, the token signature and is verification must be always in place.

Token ciphering
Database structure.

Code in charge of managing the ciphering.

Creation / Validation of the token
Use of the token ciphering during the creation and the validation of the token.

Load keys and setup cipher.

Token creation.

Token validation.

Symptom
It's occur when a application store the token in a way allowing this one to be:


 * Automatically sent by the browser (Cookie storage).
 * Retrieved even if the browser is restarted (Use of browser localStorage container).
 * Retrieved in case of XSS issue (Cookie accessible to JavaScript code or Token stored in browser local/session storage).

How to prevent

 * 1) Store the token using the browser sessionStorage container.
 * 2) Add it as a Bearer with JavaScript when calling services.
 * 3) Add fingerprint information to the token.

By storing the token in browser sessionStorage container it expose the token to be steal in case of XSS issue. However, fingerprint added to the token prevent reuse of the stolen token by the attacker on his machine. To close a maximum of exploitation surfaces for an attacker, add a browser Content Security Policy to harden the execution context.

Note:


 * The remaining case is when a attacker use the user browsing context as a proxy to use the target application through the legitimate user but the Content Security Policy can prevent communication with non expected domains.
 * It's also possible to implements the authentication service in a way that the token is issued within a hardened cookie, but in this case, a protection against Cross-Site Request Forgery attack must be implemented.

Implementation example
JavaScript code to store the token after authentication.

JavaScript code to add the token as Bearer when calling a service, for example a service to validate token here.

Symptom
It's occur when the secret used in case of HMAC SHA256 algorithm used for the token signature is weak and can be bruteforced.

The result is the capacity for an attacker to forge arbitrary valid token from a signature point of view.

See here for an example.

How to prevent
Use a very strong secret: Alphanumeric (mixed case) + special characters.

As it's a computer processing only, the size of the secret can be superior to 50 positions.

Secret example:

A&'/}Z57M(2hNg=;LE?~]YtRMS5(yZ2j:ZeX-BGftaVk`)jKP~q?,jk)EMbgt*kW'(

To evaluate the strength of the secret used for your token signature, you can apply a password dictionary attack on the token combined with the JWT API to facilitate the implementation of a breaker.

Password dictionaries can be found for example here.

Implementation example
Code in charge of testing a secret against a JWT token test base.

Code snippet to evaluate the token test base on the secret dictionary.

Use dedicated tools
You can also used JohnTheRipper to perform the password dictionary attack.

Support for Hashcat is pending.

= Authors and Primary Editors =

Jim Manico - jim.manico@owasp.org

Dominique Righetto - dominique.righetto@owasp.org

Paul Ionescu - paul.ionescu@owasp.org

= Other Cheatsheets =


 * }