JSON Web Tokens are basically a way for apps to securely pass data between the front-end (like a website or mobile app) and the back-end (the server). They package up some JSON data as a payload and digitally sign it so that the receiver can verify it hasn’t been tampered with along the way.
The JSON payload can contain all sorts of info that needs to be shared, like user details, permissions, session data, etc.
Due to it’s small size, it is transmitted quickly and can be sent through a URL, POST parameter, or in an HTTP header.
Properties of JWT
- Compact: Suitable for transmission in HTTP headers or URL parameters.
- Self-contained: Contains all necessary user or session information within the token itself.
- JSON-based: Use JSON for encoding token data, making them easy to work with.
- Extensible: Support custom claims for adding additional metadata.
- Stateless: Eliminate the need for server-side session management.
- Cryptographically secure: Can be signed and optionally encrypted for integrity, authenticity, and confidentiality.
- Standardized: Based on open standards for interoperability and wide support.
- Efficient: They are smaller in size compared to other token formats, making them suitable for various network protocols.
Format of JWT
The structure of a JSON Web Token (JWT) comprises three sections separated by periods: the header, the payload, and the signature. Here’s a breakdown:
Header.payload.signature
- Header: This part includes metadata about the token, such as its type (JWT) and the cryptographic algorithm used for the signature. It’s encoded in base64-url format and represented as JSON.
- Payload: The payload contains the claims or assertions about the user and any additional data. It’s also encoded in base64-url format and represented as JSON.
- Signature: Generated by combining the encoded header and payload with a secret key and applying the specified algorithm. The signature ensures the token’s integrity and authenticity, guarding against tampering.
A period separates each section, forming a complete JWT. Here’s a simple example:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Header: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
Payload: eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
Signature: SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
JWTs are commonly transmitted in HTTP request headers or within request bodies during authentication and authorization processes.
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.
JWT claim convention
JWT claims are typically represented as key-value pairs within the JWT payload, encoded in JSON format.
Here are some key JWT claim conventions:
- Reserved Claims:
- “iss” (Issuer): Indicates the issuer of the token, usually a URL or identifier.
- “sub” (Subject): Identifies the subject of the token, typically the user or entity the token represents.
- “aud” (Audience): Specifies the intended audience of the token, representing the recipient or recipients who are expected to consume the token.
- “exp” (Expiration Time): Defines the expiration time of the token, after which it should no longer be considered valid.
- “iat” (Issued At): Specifies the time at which the token was issued.
- “nbf” (Not Before): Defines the time before which the token should not be considered valid.
- “jti” (JWT ID): Provides a unique identifier for the token, which can be used for replay detection or tracking.
- Public Claims:
- These are standardized claims that are not reserved by the JWT specification but are commonly used and recognized within the JWT ecosystem.
- Examples include “name”, “email”, “role”, etc.
- Private Claims:
- These are custom claims defined by the application or organization using the JWT.
- Private claims should be defined in such a way as to avoid conflicts with reserved or public claims.
- They can convey additional metadata or application-specific information as needed.
Issues with authentication based on session
- Scalability: Sessions require server-side storage, which can become cumbersome as the server receives more requests. Scaling up servers adds complexity to the infrastructure.
- Session Management: Servers must track active, expired, and invalidated sessions, leading to additional overhead in managing session data.
- Performance: Each request necessitates a lookup in the session storage, impacting server performance due to the constant back-and-forth communication.
A superior solution: JSON Web Tokens (JWTs) eliminate the need for sessions, thereby mitigating the aforementioned challenges. Instead of establishing a session upon sending credentials to the server, the server issues a JWT. This token can then be utilized for authorized interactions with the server, without the burden of session management and associated performance overhead.
Signing algorithm
The most common algorithms used to sign JWTs are:
- HS256
- RS256
There are many other algorithms used to sign JWTs, you can read about them here.
Our top recommendation for maximum security is to utilize RS256. Here’s why:
- With RS256, only Auth0, the keeper of the private key, can sign tokens. Meanwhile, anyone can verify if the token is legitimate using the public key.
- If the private key is ever compromised, you can swiftly implement key rotation without needing to redeploy your application or API with a new secret. This flexibility isn’t available with HS256, where redeployment would be necessary in such a scenario.
Bypassing JSON web tokens
Bypassing JSON Web Tokens (JWTs) involves exploiting vulnerabilities or weaknesses in the authentication or authorization process. Here’s a detailed examination of common methods attackers may use to bypass JWTs:
- Information leakage
- When we use JSON web tokens (JWTs) for access control, they usually carry user-related details. However, if these tokens aren’t encrypted, anyone can easily base64 decode them and access the payload information. This means that if sensitive data is included in the token, it could potentially leak out and compromise security.
- It’s important to note that even though JWTs have a signature section, it’s primarily for ensuring data integrity, not confidentiality. In other words, the signature helps verify that the token hasn’t been tampered with, but it doesn’t prevent someone from reading its contents if they have access to the token itself.
- Changing algorithms
- RSA and HMAC are the two most commonly used algorithms for JWTs. While HMAC uses symmetric encryption (i.e. using the same key for signing and verifying), on the other hand, RSA uses asymmetric encryption (i.e. using a private key for signing and a public key for verification)
- It is important that the secret key for HMAC tokens and private key for RSA tokens is kept private, as they’re used to sign the tokens
- Suppose an application uses the RSA algorithm to sign JWT tokens. In RSA encryption, the private key which is used to sign the token is kept secret, and the public key which is used to verify the token is public.
- So a user can verify the JWT token but can’t sign it without the private key.
- But in the case of HMAC, the token is signed and verified using the same key.
- But if an attacker changes the algorithm from RSA to HMAC, she might be able to sign the token with the same key.
- None algorithm
- while the “none” algorithm was originally for debugging purposes and was never intended for operational use as a real signing algorithm.
- The vulnerability arises when developers fail to implement the recommended safeguards and permit JWTs with the insecure “none” algorithm setting.
- When the algorithm is set to “none”, JWTs are created without any cryptographic signature. this means that it can be tampered with and still be verified.
- Bruteforce, the secret key
- If secret key is known to the attacker, she can sign the token herself. If the secret key is not complex enough, then it could be brute-forced easily.
- KID tampering:
- KID stands for “Key ID.” It is a standard JWT header parameter used to indicate which key was used to sign the JWT or to provide a hint about the key that should be used to verify the signature.
- if KID parameter is not properly validated, can be exploited to perform attacks like LFI, SQLi, Path traversal, etc.
Takeaways:
In summary, JSON Web Tokens (JWTs) stand as a valuable asset for securely exchanging information within web applications. With their concise format and cryptographic signatures, JWTs provide an adaptable and efficient method for authentication and authorization, facilitating the implementation of scalable and stateless security solutions by developers. Nevertheless, it’s imperative to recognize and address potential vulnerabilities associated with JWTs, such as the risks of token forgery and expiration issues. Implementing robust security protocols, including meticulous key management, stringent token validation practices, and secure data transmission methods, is essential for mitigating these vulnerabilities effectively. As technology progresses, staying abreast of emerging trends and advancements in JWT-related practices and proactively adopting security measures will be vital for upholding the integrity and resilience of web-based systems in an ever-evolving digital environment.
References:
- https://medium.com/swlh/hacking-json-web-tokens-jwts-9122efe91e4a
- https://en.wikipedia.org/wiki/JSON
- https://www.loginradius.com/blog/engineering/jwt-signing-algorithms/
About me
Hello, I’m Harshi Gupta, a seasoned penetration tester with expertise in both internal and external assessments. Cybersecurity is not just a career path for me; it’s my hobby and passion. With a wealth of experience in identifying and mitigating security vulnerabilities, I am dedicated to ensuring the resilience of organizations’ digital assets. For networking opportunities and engaging discussions, feel free to reach out to me via LinkedIn and Twitter.