Python解密ASP.NET生成的JWT令牌遇签名验证错误,求解决
解密ASP.NET生成的加密JWT令牌问题
问题背景
需要解密ASP.NET应用生成的JWT令牌,ASP.NET端令牌生成代码如下:
public string GenerateJwtToken(ICollection<Claim> claims) { var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Identity:Jwt:SigningKey"])); var encryptionKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Identity:Jwt:EncryptionKey"])); var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha512); var expires = _systemClock.UtcNow.DateTime.AddHours(24); var issueDateTime = _systemClock.UtcNow.DateTime; var encryptingCredentials = new EncryptingCredentials( encryptionKey, JwtConstants.DirectKeyUseAlg, SecurityAlgorithms.Aes256CbcHmacSha512); var securityToken = new JwtSecurityTokenHandler().CreateJwtSecurityToken( _configuration["Identity:Jwt:Issuer"], _configuration["Identity:Jwt:Audience"], new ClaimsIdentity(claims), issueDateTime, expires, issueDateTime, signingCredentials, encryptingCredentials); return new JwtSecurityTokenHandler().WriteToken(securityToken); }
尝试使用jwcrypto库解密时,遇到错误:
jwcrypto.jws.InvalidJWSSignature: Verification failed for all signatures["Failed: [InvalidJWSSignature('Verification failed')]"]
当前Python尝试代码:
from jwcrypto import jwt, jwk, jwe import base64 s = "<Identity:Jwt:EncryptionKey>" # The same key that is used in the ASP.net app base64_bytes = base64.b64encode(s.encode("utf-8")) base64_string = base64_bytes.decode("utf-8") # Convert the Base64 string to Base64Url base64_string = base64_string.rstrip("=") base64_string = base64_string.replace("+", "-") base64_string = base64_string.replace("/", "_") print(base64_string) k = {"k": base64_string, "kty": "oct"} key = jwk.JWK(**k) token = "eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwidHlwIjoiSldUIn0..4C1FW4w2BZ6Nq5jzM1jbdQ.LJqaiSsaIxRgFw9vTs8zNhHH824JJyfU6Jmxi7hta8OyeUO11Df4HuFzC-3PyVrhI0lICtGqmY6BeaaQkquJIz65XgOi9sdR1tBNHkc5bKjTyoXxW65QbdaDhvjpFJXoe66eTPn32tf2M6VDU6w1hJitQgVpq8v11rUf2YqP0g-vkZbxTmD-Cd5BY6hHSuJ_CJ1SDIYzVGKw7mDudM0Opm9EeXEbtVZCL7YagziG_WSryfCaUh9OLulre4SOvZ8T5t5duADEn4MHiYRUZjNbXZIhsWsLfxhINhspekoS4ha8rYQSIHH8208TD4wckQ3zx70XYNHbQiqSr3Atlt-zXPIG1MsfXZJOrg4-KFeKaWxlMfyx3iPiSRisILQm-ATGDnRxHewEuU0gwLyHkwTsyObO7zIuDs82RMgCB5jFs-PK27YHPplv26w9WDQ1F88Lbiumxv9j1zvF6rTQEFte7OnHJD9BpxTDmC9vvUNbdsBLn2tlhAtWKU-oBUOtA-vJIiWz3lt_Mz5Xj1G9WlcHtcUNi-kv_ZFDz45gmG-nhvHDZE3Sp8qnyko8W6tmDusXI6nTwseQ3FrQgUCR69jJ_bEvGjGzqrJ2Pv0qFcyNuHZglB8CvX3kALoMeRyYuV_ULD0wEDd8QET-w_6gKj1-aPfGqcWbJO0JRxphWNJcVLcicoe3fWqyXrmv6iPWZsKcmEYE2T3qco3dVeoYgC-EkPBROfHXzvBdb9ABqfW2dc782fPHXhahZkJJNfXaxNC6Lc8COe-DjQVUtU-z-VL6erhmgzb-G178A074q3kX2b1nDp4zEMs4t704SEdSyo4uKzamKwXtbc_XwKb-Xcda_udoWhW1KiQkJktHhYnZ6g1dcUjQ0G5R9P8hX3T597mNJyHq8lVr6hYhWXRZZLm_1w.VL2-nxFdi3b3-lUy-Oi0sQOPTwgVmdIkLV9TLBYNYUs" ET = jwt.JWT(key=key, jwt=token, expected_type="JWE") print(ET.claims) ST = jwt.JWT(key=key, jwt=ET.claims) print(ST.claims)
问题原因
- 密钥混用:ASP.NET生成的是嵌套JWT(JWE包裹JWS),解密JWE需要用
EncryptionKey,验证内部JWS需要用SigningKey,当前代码用加密密钥去验证签名,导致验证失败。 - 密钥编码错误:手动转换Base64到Base64Url容易出错,jwcrypto提供了更可靠的密钥构建方法。
正确解密代码
from jwcrypto import jwt, jwk # 替换为ASP.NET配置中的实际密钥 ENCRYPTION_KEY = "<Identity:Jwt:EncryptionKey>" SIGNING_KEY = "<Identity:Jwt:SigningKey>" # 1. 构建加密密钥,解密JWE encryption_jwk = jwk.JWK.from_bytes(ENCRYPTION_KEY.encode('utf-8'), kty='oct') token = "eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwidHlwIjoiSldUIn0..4C1FW4w2BZ6Nq5jzM1jbdQ.LJqaiSsaIxRgFw9vTs8zNhHH824JJyfU6Jmxi7hta8OyeUO11Df4HuFzC-3PyVrhI0lICtGqmY6BeaaQkquJIz65XgOi9sdR1tBNHkc5bKjTyoXxW65QbdaDhvjpFJXoe66eTPn32tf2M6VDU6w1hJitQgVpq8v11rUf2YqP0g-vkZbxTmD-Cd5BY6hHSuJ_CJ1SDIYzVGKw7mDudM0Opm9EeXEbtVZCL7YagziG_WSryfCaUh9OLulre4SOvZ8T5t5duADEn4MHiYRUZjNbXZIhsWsLfxhINhspekoS4ha8rYQSIHH8208TD4wckQ3zx70XYNHbQiqSr3Atlt-zXPIG1MsfXZJOrg4-KFeKaWxlMfyx3iPiSRisILQm-ATGDnRxHewEuU0gwLyHkwTsyObO7zIuDs82RMgCB5jFs-PK27YHPplv26w9WDQ1F88Lbiumxv9j1zvF6rTQEFte7OnHJD9BpxTDmC9vvUNbdsBLn2tlhAtWKU-oBUOtA-vJIiWz3lt_Mz5Xj1G9WlcHtcUNi-kv_ZFDz45gmG-nhvHDZE3Sp8qnyko8W6tmDusXI6nTwseQ3FrQgUCR69jJ_bEvGjGzqrJ2Pv0qFcyNuHZglB8CvX3kALoMeRyYuV_ULD0wEDd8QET-w_6gKj1-aPfGqcWbJO0JRxphWNJcVLcicoe3fWqyXrmv6iPWZsKcmEYE2T3qco3dVeoYgC-EkPBROfHXzvBdb9ABqfW2dc782fPHXhahZkJJNfXaxNC6Lc8COe-DjQVUtU-z-VL6erhmgzb-G178A074q3kX2b1nDp4zEMs4t704SEdSyo4uKzamKwXtbc_XwKb-Xcda_udoWhW1KiQkJktHhYnZ6g1dcUjQ0G5R9P8hX3T597mNJyHq8lVr6hYhWXRZZLm_1w.VL2-nxFdi3b3-lUy-Oi0sQOPTwgVmdIkLV9TLBYNYUs" # 解密JWE得到内部JWS令牌 jwe_token = jwt.JWT(key=encryption_jwk, jwt=token, expected_type="JWE") jws_token_str = jwe_token.claims # 2. 构建签名密钥,验证JWS并解析声明 signing_jwk = jwk.JWK.from_bytes(SIGNING_KEY.encode('utf-8'), kty='oct') jws_token = jwt.JWT(key=signing_jwk, jwt=jws_token_str, expected_type="JWS") print("解密并验证后的声明:") print(jws_token.claims)
关键注意事项
- 严格区分
EncryptionKey和SigningKey,两者功能不同不可混用。 - 使用
jwk.JWK.from_bytes自动处理密钥编码,避免手动转换出错。 - 解密时指定
expected_type="JWE",验证时指定expected_type="JWS",确保库正确识别令牌类型。
内容的提问来源于stack exchange,提问作者Mohamad Fadil
相关产品推荐
相关产品推荐

