JWS JSON integrity protected headers are owerwritten by unprotected headers

Describe the bug

Deserialize JWS JSON will overwrite protected headers (protected) with values from header

To Reproduce

from authlib.jose import JsonWebSignature


jws = JsonWebSignature()

header_obj = {
    'protected': {
        'alg': 'HS256',
        'crit': ['jti', 'exp'],
        'kid': 'key',
        'jti': '1',
        'exp': '11111111111',
    },
    'header': {},
}
secret = b'secret'
payload = b'payload'

jws_json = jws.serialize_json(header_obj, payload, secret)

# assume that attacker got access to jws
jws_json['header'] = {
    'kid': 'another_key',
    'jti': '9',
    'exp': '99999999999',
}

decoded = jws.deserialize_json(jws_json, secret)

assert decoded['header']['kid'] == 'key'
assert decoded['header']['jti'] == '1'
assert decoded['header']['exp'] == '11111111111'

Expected behavior

deserialize_json must not overwrite protected headers with unprotected headers.

{
    'header': {
        'alg': 'HS256',
        'crit': ['jti', 'exp'],
        'kid': 'key',
        'jti': '1',
        'exp': '11111111111'
    },
    'payload': b'payload',
}

Environment:

  • OS: ox X 11.2.3
  • Python Version: 3.9.1
  • Authlib Version: 0.15.3