JWT: A Cryptographic Love Story with Security, Vulnerabilities, and a State of Confusion
Folks, remember to be careful with your JWTs. Use strong cryptographic algorithms, manage those secret keys like they're your firstborn child, and always, always validate those JWTs like your life depends on it. And for goodness' sake, keep your sensitive information under lock and key!
Imagine you are a person travelling through the vast expanse of the universe, carrying important information and data that you need to share with others along the way. However, in this vast and treacherous landscape, you need a way to protect this data and ensure that only those who are authorized can access it.
Enter JWT, a clever and simple way to protect your data using cryptography. With JWT, you can encode your data into a compact and self-contained format, which includes a signature that can be verified to ensure that the data has not been tampered with. This signature is like a lock on a suitcase, protecting the contents inside from unauthorized access.
But JWT is not just about security. It also allows you to transmit data quickly and efficiently, without the need for complex authentication protocols or lengthy handshakes. By including all the necessary information in the JWT itself, you can send and receive data with ease, like a cosmic messenger carrying vital information across the universe.
And the beauty of JWT is that it is flexible and adaptable to many different scenarios. You can use different cryptographic algorithms, such as symmetric or asymmetric encryption, to suit your needs. You can also include a variety of claims and metadata in the JWT, such as expiration times, audience information, and more, to further enhance its functionality.
JWT is like a cosmic messenger that allows you to protect, transmit, and verify data in the vast expanse of the universe. With JWT, you can rest assured that your data is secure and can be easily shared with those who are authorized to receive it.
Let's talk about the vulnerabilities of JWTs! I mean, sure, they have their benefits, but let's not forget that these bad boys can be cracked wide open if you're not careful.
For starters, the use of symmetric signatures is like putting all your eggs in one basket. If someone manages to get their hands on that secret key, they can mess with your JWTs and cause all sorts of trouble. It's like leaving the front door to your house unlocked and wondering why someone stole all your stuff!
And let's not forget about the validation process. If you're not careful, you might as well be giving out free passes to your data. If the validation process isn't done right, someone could slip in a forged JWT and you'd be none the wiser. It's like letting your weird cousin Gary watch your dog while you're on vacation - you never know what kind of shenanigans he's going to get up to!
And last but not least, you gotta be careful with what you put in your JWT payload. If it's sensitive information, like your social security number or your credit card info, you might as well be throwing a party for identity thieves. It's like writing your PIN number on a piece of paper and sticking it to your forehead!
4 technical use cases
First let's be specific about the roles of private & public key pairs, shared secret key, and digital certificates, then how JWT could be used for these four JWT combinations:
- Asymmetric signature and asymmetric encryption (JWE): In this case, the sender would use their private key to sign the JWT, and the recipient would use the sender's public key to verify the signature. The sender would also encrypt the payload using the recipient's public key and include the encrypted payload in the JWT. The recipient would use their private key to decrypt the payload and retrieve the original claims. The sender's public key would be distributed with a digital certificate signed by a trusted CA, and the recipient would verify the certificate chain to ensure the sender's public key is authentic and has not been tampered with.
- Shared key for symmetric signature and separate shared key for symmetric encryption (JWE): In this case, the sender would use a shared secret key to sign the JWT, and the recipient would use the same shared secret key to verify the signature. The sender would also encrypt the payload using a different shared secret key and include the encrypted payload in the JWT. The recipient would use the same shared secret key to decrypt the payload and retrieve the original claims. Digital certificates would not be used in this scenario, as symmetric keys are not typically distributed using certificates.
- Shared key for symmetric signature but no encryption: In this case, the sender would use a shared secret key to sign the JWT, and the recipient would use the same shared secret key to verify the signature. Digital certificates would not be used in this scenario, as symmetric keys are not typically distributed using certificates.
- Key pair for asymmetric signature but no encryption: In this case, the sender would use their private key to sign the JWT, and the recipient would use the sender's public key to verify the signature. Digital certificates would be used to distribute the sender's public key, signed by a trusted CA, to ensure its authenticity and integrity.
And the use cases for each:
- Asymmetric signature and asymmetric encryption (JWE): This combination is typically used when the sender and recipient of the JWT are not trusted parties, and there is a need to secure the contents of the JWT. For example, a healthcare application that transmits patient information between doctors and hospitals could use this combination to ensure that the information is kept confidential and is not tampered with.
- Shared key for symmetric signature and separate shared key for symmetric encryption (JWE): This combination is often used in situations where the sender and recipient of the JWT are trusted parties, but there is a need to keep the contents of the JWT confidential. For example, a messaging application that allows users to send encrypted messages to each other could use this combination to ensure that the messages are kept confidential between the sender and recipient.
- Shared key for symmetric signature but no encryption: This combination is typically used when the sender and recipient of the JWT are trusted parties, and there is no need to keep the contents of the JWT confidential. For example, a web application that uses JWTs for user authentication could use this combination to sign the JWT and ensure that it has not been tampered with, without the need for encryption.
- Key pair for asymmetric signature but no encryption: This combination is often used when the sender and recipient of the JWT are not trusted parties, and there is a need to ensure the authenticity and integrity of the JWT. For example, a banking application that allows customers to perform transactions could use this combination to sign the JWT and ensure that it has not been tampered with, while also using digital certificates to ensure the authenticity and integrity of the sender's public key.
The security bits
The security characteristics of JWT signatures (a cryptographic signature) include:
- Integrity: A JWT signed with a symmetric signature guarantees that the payload has not been altered in any way, as any change to the payload will result in an invalid signature.
- Authenticity: The recipient of a JWT can be confident that the sender who created the JWT is the one who they claim to be, as only the sender and recipient know the shared secret key used to sign and verify the JWT.
- Efficiency: Symmetric signature is a fast and efficient way to verify the authenticity and integrity of a JWT, as it involves fewer steps compared to asymmetric signature.
However, a cryptographic signature has some limitations and vulnerabilities, such as:
- Key management: The shared secret key used for signing and verifying the JWT must be kept secret and known only to the sender and recipient. If the key is compromised, an attacker can create and sign their own JWTs, impersonating the sender.
- Lack of non-repudiation: A JWT signed with a symmetric signature cannot provide non-repudiation, meaning that the sender can later deny that they created or signed the JWT.
- Key distribution: Distributing the shared secret key to all parties who need to verify the JWT can be challenging, as the key must be kept secret and transmitted securely.
Asymmetric cryptographic signature provides several security characteristics, guarantees, and assurances, which include:
- Authentication: The signature guarantees that the message is coming from the claimed sender and has not been modified during transmission.
- Non-repudiation: The signature assures that the sender cannot deny sending the message.
- Integrity: The signature ensures that the message has not been tampered with or modified in any way during transmission.
- Confidentiality: Asymmetric signature itself does not provide confidentiality as it only ensures the authenticity and integrity of the message. However, the message can be encrypted using the recipient's public key to provide confidentiality.
- Key distribution: Asymmetric signature enables secure key distribution by allowing the sender to distribute their public key to recipients without revealing their private key.
- Trust: Asymmetric signature uses a trusted third party, known as a Certificate Authority (CA), to validate the authenticity of the sender's public key, which enhances trust in the communication.
Overall, asymmetric cryptographic signature provides strong security guarantees and assurances, which make it suitable for various security-critical applications, such as secure messaging, digital signatures, and secure authentication. While the asymmetric cryptographic signature offers many security benefits, it also has some limitations, vulnerabilities, and challenges. Here are a few:
- Key Management: Asymmetric cryptography relies heavily on the management of public and private keys. If the private key is compromised or stolen, the security of the system is compromised. Ensuring secure key storage and management can be a challenge.
- Processing Overhead: Asymmetric cryptography can be computationally intensive, especially when compared to symmetric cryptography. This can make it challenging to implement in systems that require high performance.
- Complexity: Asymmetric cryptography is more complex than symmetric cryptography, which can make it more difficult to implement and maintain.
- Man-in-the-Middle Attacks: Asymmetric cryptography can be vulnerable to man-in-the-middle attacks if the public key is not properly authenticated. An attacker can intercept the communication and replace the public key with their own, allowing them to intercept and decrypt messages.
- Implementation Errors: Asymmetric cryptography is only as secure as its implementation. If there are errors in the implementation, such as incorrect key lengths or algorithms, the security of the system can be compromised.
- Length of Keys: Asymmetric cryptography requires longer keys than symmetric cryptography to achieve the same level of security. This can make key distribution and storage more challenging.
Overall, while the asymmetric cryptographic signature provides many benefits, it is important to understand and address its limitations and vulnerabilities to ensure the security of the system.
In any JWT signature algorithm, the input to the signature generation process is a string called the "canonical string", which is formed by concatenating the header and payload sections of the JWT with a period (".") separator. This string is then signed using a secret key to produce the signature.
Therefore, any changes to the claims in the payload section of the JWT will result in a different canonical string being generated, which in turn will produce a different signature hash when signed with the same secret key.
More specifically; the JWT claims that are input to the canonical string to generate the signature hash are the claims in the payload section of the JWT, which typically include information about the user or client, and any additional custom data that needs to be transmitted. These claims can include standard registered claims like "iss" (issuer), "exp" (expiration time), "sub" (subject), and "aud" (audience), as well as any custom claims defined by the developer but are all exposed completely in the clear.
What!? no Confidentiality!? You lie, sir!!!
Confidentiality is an important aspect of information security, but it is not directly related to the JWT signature mechanism itself. Rather, confidentiality is achieved through encryption, which is typically used in conjunction with signature-based authentication to provide a secure end-to-end communication.
In JWT, confidentiality can be achieved through the use of encryption via JWE (JSON Web Encryption) where the payload is encrypted using a symmetric key or the recipient's public key, and the encrypted payload is included in the JWT. The recipient uses their private key or the shared secret key to decrypt the payload and retrieve the original claims. This ensures that the payload is kept confidential and is not visible to any unauthorized parties.
There is no Authorization
Wait! JWT are not used for Authorization!? That can't be true, I read it on Stack Overflow!
Unauthorized access is not just a security concern, it is the foundational skill for almost all software that every developer faces continuously and according OWASP Top 10:2021 (is a data driven report) the most common security flaws are directly associated to defects in code that is meant to ensure access control. Authz relates to both authentication and access control (and Authz is nothing without both), and it is not a design goal or inherent property of JWT signatures at all (or any kind of cryptographic signature).
JWT or any cryptographic signature are only used to verify the authenticity and integrity of the a signed message, but they do not determine who is authorized to access the resource or perform the action. This is typically handled by other mechanisms such as access control lists (ABAC, RBAC, etc. [*]BAC strategies). However, if a JWT is compromised, an attacker could use the token to impersonate a legitimate user and gain unauthorized access (the [*]BAC strategy trusted the authenticity of the JWT) to protected resources that identity had authorized access to. Therefore, it is important to handle JWTs with care and follow the specification directions for token management and revocation.
This Auth0 resource provides a comprehensive overview of JWT, including how it can be used for authentication and provide a means for your own implementation achieving authorization, and what types of claims can be included in a JWT. It also explains how JWT can help mitigate certain security risks such as CSRF attacks.
The main benefit of encryption is to provide confidentiality by ensuring that only authorized parties with the appropriate decryption key can read the encrypted data. By encrypting sensitive data, you can help ensure that it remains confidential and protected from unauthorized access, even if it falls into the wrong hands.
Oh, no biggie, you know. Just hand over your private key to someone else and watch your confidentiality disappear into thin air. Don't worry about it, though. It's not like your sensitive information is worth protecting or anything.
If you did not generate the private key and it is not within your control or visibility into how it is generated or who has access to it, then you would need to rely on other mechanisms to gain assurance of the secure storage and management of that key. In JSON Web Encryption (JWE), the encrypted payload of the JWT, which includes the claims, is encrypted using a specific encryption algorithm and a key. The encryption algorithm determines the encryption method used to encrypt the payload, while the key is used to perform the encryption and decryption.
There are two types of keys used in JWE: symmetric keys and asymmetric keys.
There are TWO types of keys: symmetric and asymmetric KEYS but 4 combinations of key for encryption or signature verification purposes where you may have more than 1 key per token use. We are just focusing on encryption here, NOT signature verification (this is very important!)
- Symmetric keys: In symmetric encryption, the same key is used for both encryption and decryption. The symmetric key is typically a secret shared between the sender and recipient. When a recipient receives a JWE, they use the shared symmetric key to decrypt the payload and retrieve the original claims.
- Asymmetric keys: In asymmetric encryption, there are two keys: a public key and a private key. The sender uses the recipient's public key to encrypt the payload, and the recipient uses their private key to decrypt it. Asymmetric encryption is often used in scenarios where the sender does not have access to a shared symmetric key, or when the recipient's public key can be trusted to encrypt the payload.
When encrypting the claims within a JWT, the key used for encryption will depend on the encryption algorithm being used. There are several symmetric encryption algorithms that can be used for JSON Web Encryption (JWE), each with its own strengths and weaknesses. Here are some common symmetric encryption algorithms used in JWE:
- AES-CBC (Advanced Encryption Standard - Cipher Block Chaining): This encryption algorithm is widely used and offers a good balance between security and performance. AES-CBC encrypts the payload in blocks of 128 bits, with each block being XORed with the previous block before encryption. The initialization vector (IV) used for encryption is included in the JWE header.
- AES-GCM (Advanced Encryption Standard - Galois/Counter Mode): This encryption algorithm provides both encryption and authentication of the payload, which can be useful for detecting any tampering with the JWE. AES-GCM encrypts the payload in blocks of 128 bits, and the IV is included in the ciphertext.
- ChaCha20-Poly1305: This encryption algorithm is a newer addition to JWE and offers similar security to AES-GCM, but with faster performance. ChaCha20-Poly1305 encrypts the payload in blocks of 64 bits and includes the nonce (similar to the IV in other algorithms) in the JWE header.
The key may be a symmetric key shared between the sender and recipient, or it may be an asymmetric key pair consisting of a public key and a private key. The recipient will use the appropriate decryption algorithm and key to decrypt the ciphertext and retrieve the original payload containing the claims. When using symmetric encryption in JWE, it's important to choose an encryption algorithm that provides appropriate security for the information being transmitted and to use a strong shared secret key that is kept secure and not easily guessable. One such mechanism is the use of digital certificates and public key infrastructure (PKI).
Digital certificates are issued by trusted third-party organizations, called Certificate Authorities (CAs), and are used to authenticate the identity of entities in a secure manner. Digital certificates can also be used to securely distribute and manage cryptographic keys, including private keys. When a private key is distributed with a digital certificate, the certificate contains information about the entity that owns the private key and is signed by a trusted CA.
To gain assurance of the secure storage and management of a private key that you did not generate, you can verify the digital certificate associated with the key. This can be done by checking the certificate chain and verifying that it is issued by a trusted CA. You can also check for any revocation information associated with the certificate, which can indicate whether the private key has been compromised or revoked.
Another mechanism is the use of standards and best practices for key management, such as the Key Management Interoperability Protocol (KMIP) and the National Institute of Standards and Technology (NIST) key management guidelines. By ensuring that the entity that generated the private key is following these standards and best practices, you can gain assurance of the secure storage and management of the key.
For example, suppose an application uses JWTs to authenticate users and authorizes them to access specific resources. If the application uses the same secret to sign all JWTs, any user who gains access to that secret can generate a valid token and gain access to another user's resources.
To avoid this issue, it's recommended to use a unique secret for each user or at least for each user role, so that each user or role has its own private key to sign JWTs. This ensures that only authorized users can generate valid tokens and access resources. Additionally, it's important to keep the secret key secure and not share it with anyone who should not have access to it.
Overall, while you may not have direct control or visibility over the private key that you did not generate, there are still technical mechanisms that can be used to gain assurance of its secure storage and management.
However, it's important to note that encryption alone does not provide complete security. For example, an attacker who gains access to the recipient's decryption key or the encrypted data before it is encrypted could still gain access to the sensitive information. Therefore, encryption should be used in combination with other security measures, such as access control, authentication, and secure key management, to provide comprehensive data protection.
Here are some links to developer guides on using JWTs with various programming languages:
- JSON Web Token (JWT) - Introduction: This is the official guide for using JWTs with Java: https://jwt.io/introduction/
- Auth0 JWT Documentation: This guide provides detailed information on using JWTs with various programming languages and frameworks, including Node.js, Java, Ruby, Python, and more: https://auth0.com/docs/jwt
- Microsoft Azure JWT Documentation: This guide provides information on using JWTs with .NET, Java, Node.js, and other programming languages: https://docs.microsoft.com/en-us/azure/active-directory/develop/access-tokens
- Django Rest Framework JWT Authentication: This is a guide for using JWTs with Django, a popular Python web framework: https://jpadilla.github.io/django-rest-framework-jwt/
- Flask-JWT: This is a guide for using JWTs with Flask, another popular Python web framework: https://pythonhosted.org/Flask-JWT/
- JWT specification document on the IETF website which provides detailed information about using JWTs: https://datatracker.ietf.org/doc/html/rfc7519
Well, well, well, look at us trying to be all serious and technical with our talk of JWTs and cryptographic signatures. It's like we're trying to impress someone or something. But let's be real, the only thing we're impressing is our computers.
We started off by talking about the benefits of JWTs and how they can be used to securely transmit information between parties. Then we went on to discuss the different methods of implementing cryptographic signatures, both symmetric and asymmetric. We even talked about real-world use cases for each method.
But let's not forget the vulnerabilities and limitations of these methods. We discussed the potential for unauthorized access and the importance of properly validating JWTs on the recipient side. We also talked about the challenges and potential weaknesses of using asymmetric signatures.
Overall, we've covered a lot of ground but let's not get too carried away with our technical jargon. At the end of the day, we're just a bunch of humans trying to make sense of this crazy digital world.