验证JWT签名时的SecurityTokenSignatureKeyNotFoundException
本文关键字:SecurityTokenSignatureKeyNotFoundException JWT 验证 | 更新日期: 2023-09-27 18:12:21
我正试图为我的组织实现OpenID连接规范。我在一个测试依赖方应用程序中使用微软的OpenID Connect的OWIN实现来验证我对协议的实现。
我已经公开了以下元数据文档:
{
"issuer": "https://acs.contoso.com/",
"authorization_endpoint": "http://localhost:53615/oauth2/auth",
"token_endpoint": "http://localhost:53615/oauth2/token",
"userinfo_endpoint": "http://localhost:53615/connect/userinfo",
"jwks_uri": "http://localhost:53615/connect/keys",
"ui_locales_supported": [
"en-GB"
]
}
签名密钥公开为以下文档:
{
"keys": [
{
"n": "xpXxl3M-YkZlzQJdArO1TfOGT2no-UL4dbZ7WuSCNIsSfyGDaqUXjMMHNyq9yD3vp-NCyk8kmn7d5XqHufnceXJM8q4xTrhN3lvywdBSbR-dwXsA-B-MJVgfiK0d_z-mxP9ew2Hj9-KkWbWCzsswlWp3gZ4mB4RGutB1IRSzXVIbvZ-MtKUb6XUDU4LDb_c1xCEXWZxhR-o1a1dLfObH2hHJ-w5y6odGlKtOFx4i4h0u7-Oj5R6k5b2YXEHM0IuYeN0u0sQvrTecokntGzPrvhnKy69I7Z_az5rC5kgloh25D9lTbe4vcRU7FXlYCFYDZsT0_IkGIXRi7brOS4f1ow",
"e": "AQAB",
"kty": "RSA",
"use": "sig",
"alg": "RS256",
"kid": "F8A59280B3D13777CC7541B3218480984F421450"
}
]
}
使用JwtSecurityToken
类及其关联的处理程序(使用X509SigningCredentials
类)生成身份令牌。此代码代表了如何构造令牌并将其作为响应数据的参数返回给调用系统。
var credentials = new X509SigningCredentials(cert); // My certificate.
var issuedTime = DateTime.UtcNow;
var expiresTime = issuedTime.AddMinutes(5);
var epoch = new DateTime(1970, 01, 01, 0, 0, 0);
var claims = new[]
{
new Claim("sub", Guid.NewGuid().ToString()),
new Claim("iat" Math.Floor((issuedTime - epoch).TotalSeconds).ToString()),
new Claim("nonce", nonce), // Value from client
}
var token = new JwtSecurityToken(
"https://acs.contoso.com",
client_id, // Value from client
claims,
new Lifetime(issuedTime, expiresTime),
credentials);
var handler = new JwtSecurityTokenHandler();
parameters.Add("id_token", handler.WriteToken(token)); // Outgoing parameters.
当我尝试将签名令牌传递回依赖方应用程序时,OWIN中间件接受POST并尝试验证令牌的签名。在这样做时,会抛出以下异常:
SecurityTokenSignatureKeyNotFoundException: IDX10500:签名验证失败。无法解析SecurityKeyIdentifier:'SecurityKeyIdentifier (IsReadOnly = False, Count = 1, Clause[0] = .X509ThumbprintKeyIdentifierClause(散列=0 xf8a59280b3d13777cc7541b3218480984f421450))",令牌:"{typ":"JWT"、"alg":"RS256"、"x5t":"-KWSgLPRN3fMdUGzIYSAmE9CFFA"},{"空间站":"https://test.accesscontrol.net/","澳大利亚":"测试"、"nbf":1404917162,"实验":1404917462,"子":"60 eb55ec - 0699 - 4068 - bfa6 - 41666 - fc2b2e9"、"iat":"1404917162"}RawData:eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ii1LV1NnTFBSTjNmTWRVR3pJWVNBbUU5Q0ZGQSJ9.eyJpc3MiOiJodHRwczovL2Fjcy5zdXJlY2xvdWQuY29tLyIsImF1ZCI6InRlc3QiLCJuYmYiOjE0MDQ5MTcxNjIsImV4cCI6MTQwNDkxNzQ2Miwic3ViIjoiNjBlYjU1ZWMtMDY5OS00MDY4LWJmYTYtNDE2NjZmYzJiMmU5IiwiaWF0IjoiMTQwNDkxNzE2MiJ9.xkP0RwlX3CYfU0KhFsVvLJC94WK22DTqNTm71cfjiJ8VUHv3b2YhDqfq70N8mQEyiR8vTR6OQqnO6UqXqX4RXUs6ZkfK9Liv3n9NhCs97wJhP2jfefJYeScYtRmWcNNWSSL7vkm2JXQfwKOQTnOGp-ba04TtI6jVrjhOQXH43eCJ9vNuBUzdD-t8CAdmnbvH0nWpIB8kWbw5v8Sa0aQuxMjJYbLC_2Iw3X13dqnyVjp4fA7eSB8N7c1it0KEB-VKfUqiGD3VecyEZGGZbaGE8rvVet5QrY1lJ3V4yM8j6-xDc5Yndc4swOun0L3D6TYk-8gdVXUJDRjbv1ZuhZltsw"。
该组件仍然是预发布的,所以这可能是实现中的一个缺陷,但是我想假设这是我的错误,直到所有的可能性都被排除。
是否有任何我正在做的显然是错误的,或者我应该做些什么来理解为什么签名未能被验证?
问题隐藏在这里的异常消息中:
Clause[0] = X509ThumbprintKeyIdentifierClause(Hash = 0xF8A59280B3D13777CC7541B3218480984F421450)
令牌是用X.509证书的默认密钥标识子句签名的:它的指纹。元数据只公开RSA参数和名称标识符。当客户端检索元数据时,它使用此信息设置RSA密钥,而不是X.509拇指指纹。
要纠正此错误,必须更改签名凭据以包含正确的名称标识符:
var credentials = new X509CertificateCredentials(
cert,
new SecurityKeyIdentifier(
new NamedKeySecurityKeyIdentifierClause(
"kid",
"F8A59280B3D13777CC7541B3218480984F421450")));
包含签名中期望的标识符,并且签名验证成功。
我遇到过这个异常。在我的例子中,我们的应用程序缓存来自Azure环境的签名密钥,因为它们不经常更改,但是没有机制来刷新密钥。由于签名密钥最终会轮换,所以我们接收到的是有效的JWT,但是有一个旧的签名密钥列表,在这种情况下,它们都无法验证JWT签名。