在 c# 中使用 ---PUBLIC KEY--- 验证 JWT (ES256) 令牌
Posted
技术标签:
【中文标题】在 c# 中使用 ---PUBLIC KEY--- 验证 JWT (ES256) 令牌【英文标题】:Validate JWT (ES256) Token with ---PUBLIC KEY--- in c# 【发布时间】:2020-03-31 08:16:54 【问题描述】:我有一个由我的 AWS ALB 使用 OpenID 连接器创建的 JWT。我需要在我的 c# 应用程序中验证令牌。但我很难让它发挥作用。
AWS 在此处描述令牌验证:https://docs.aws.amazon.com/elasticloadbalancing/latest/application/listener-authenticate-users.html?icmpid=docs_elbv2_console
它应该分三步工作:
从令牌中获取密钥 id 从 aws alb enpoint(https://public-keys.auth.elb.' + region + '.amazonaws.com/' + key id)
读取公钥
使用密钥解密负载
这是我得到的 JWT:
eyJ0eXAiOiJKV1QiLCJraWQiOiJjODE4ZTcxNi01OTAxLTQzOWQtOWFlZC1lYmRmODAyYjZkYTkiLCJhbGciOiJFUzI1NiIsImlzcyI6Imh0dHBzOi8vc2llbWVucy1xYS0wMDA2OS5ldS5hdXRoMC5jb20vIiwiY2xpZW50IjoiMndsS3k0YlRXbGpZWm9KYXZRSVFqVTE3OUprVG4zNDAiLCJzaWduZXIiOiJhcm46YXdzOmVsYXN0aWNsb2FkYmFsYW5jaW5nOmV1LWNlbnRyYWwtMTo0ODU2ODM0ODcxOTY6bG9hZGJhbGFuY2VyL2FwcC9maW5kLXRlc3QtYWxiLzU3YzBmMWYzZjg0YzZjMjEiLCJleHAiOjE1NzU1NDMwMzN9.eyJzdWIiOiJvYXV0aDJ8bWFpbi10ZW5hbnQtb2lkY3xzYW1scHxTaWVtZW5zfFowMDJFSk5VIiwiZ2l2ZW5fbmFtZSI6IlJhcGhhZWwiLCJmYW1pbHlfbmFtZSI6IlNjaG5haXRsIiwibmlja25hbWUiOiJSYXBoYWVsIiwibmFtZSI6IlJhcGhhZWwgU2NobmFpdGwiLCJwaWN0dXJlIjoiaHR0cHM6Ly9zLmdyYXZhdGFyLmNvbS9hdmF0YXIvODkzNWVlY2QzMDc2ZTAyMTQ5ODE2MTZmZjBkZTRkZjI_cz00ODAmcj1wZyZkPWh0dHBzJTNBJTJGJTJGY2RuLmF1dGgwLmNvbSUyRmF2YXRhcnMlMkZyYS5wbmciLCJ1cGRhdGVkX2F0IjoiMjAxOS0xMi0wNVQxMDo0ODozMy4wNjhaIiwiZXhwIjoxNTc1NTQzMDMzLCJpc3MiOiJodHRwczovL3NpZW1lbnMtcWEtMDAwNjkuZXUuYXV0aDAuY29tLyJ9.M39aPefXmaDGzaDd0qHcQHMhvugTVN4i4pyvGJ-7fayewU9vZdtKvSzFF9rVal8GEz7HKTr_auqMw9HemOW yag==
因此,密钥 ID 为:c818e716-5901-439d-9aed-ebdf802b6da9
公钥:
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENARdEGaEpfgHph3440UodVsQdqxi
PYz+l1aEcz+Bivr6emXDnor1nET94dbPqYxk+vtUHGkgOb44VPEZUe4ijQ==
-----END PUBLIC KEY-----
我尝试使用以下方法验证代码:
使用System.IdentityModel.Tokens.Jwt
命名空间。但是我无法将公钥作为字符串提供给 ValidationParameters。我遵循了这个答案https://***.com/a/51866939/2250672 的类似方法。感觉很复杂而且容易出错。由于一整天后我无法让它工作,我决定继续使用其中一个提供相同功能的 nuget 包。
使用 JWT nuget 包,但不支持 AWS ALB 使用的算法。
使用 Jose.JWT nuget Package 使用以下代码:
Jose.JWT.Decode(__token, publicKeyPem, Jose.JwsAlgorithm.ES256)
得到以下错误:
错误:脚本执行失败。 [ArgumentException] EcdsaUsingSha 算法要求密钥为 CngKey 或 ECDsa 类型。
如何在 C# 中简单地从 AWS ALB 验证 JWT?
【问题讨论】:
您的 JWT 由https://siemens-qa-00069.eu.auth0.com/
发布。您为什么要尝试根据 AWS 密钥对其进行验证?
因为 JWT 是由 aws 负载均衡器生成的。
你如何解释智威汤逊有https://siemens-qa-00069.eu.auth0.com/
作为发行人?
我想验证签名者,它在 jwt 中被称为签名者,“签名者”:“arn:aws:elasticloadbalancing:eu-central-1:485683487196:loadbalancer/app/find-test -alb/57c0f1f3f84c6c21"。这就是我尝试根据 AWS 密钥验证它的原因。如果您尝试在 jwt.io 上使用公钥,您会看到它显示有效。 (您需要从签名中删除尾部的=
)
【参考方案1】:
https://siemens-qa-00069.eu.auth0.com/.well-known/openid-configuration 上没有公钥。因此,您可以尝试手动方法:
private static ECDsa LoadPublicKey(byte[] key)
byte[] pubKeyX = key.Skip(27).Take(32).ToArray();
byte[] pubKeyY = key.Skip(59).Take(32).ToArray();
return ECDsa.Create(new ECParameters
Curve = ECCurve.NamedCurves.nistP256,
Q = new ECPoint
X = pubKeyX,
Y = pubKeyY
);
string key = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENARdEGaEpfgHph3440UodVsQdqxiPYz+l1aEcz+Bivr6emXDnor1nET94dbPqYxk+vtUHGkgOb44VPEZUe4ijQ==";
ECDsa ecdsa = LoadPublicKey(Convert.FromBase64String(key));
string authorizationDomain = "https://siemens-qa-00069.eu.auth0.com/";
string jwt = "eyJ0eXAiOiJKV1QiLCJraWQiOiJjODE4ZTcxNi01OTAxLTQzOWQtOWFlZC1lYmRmODAyYjZkYTkiLCJhbGciOiJFUzI1NiIsImlzcyI6Imh0dHBzOi8vc2llbWVucy1xYS0wMDA2OS5ldS5hdXRoMC5jb20vIiwiY2xpZW50IjoiMndsS3k0YlRXbGpZWm9KYXZRSVFqVTE3OUprVG4zNDAiLCJzaWduZXIiOiJhcm46YXdzOmVsYXN0aWNsb2FkYmFsYW5jaW5nOmV1LWNlbnRyYWwtMTo0ODU2ODM0ODcxOTY6bG9hZGJhbGFuY2VyL2FwcC9maW5kLXRlc3QtYWxiLzU3YzBmMWYzZjg0YzZjMjEiLCJleHAiOjE1NzU1NDMwMzN9.eyJzdWIiOiJvYXV0aDJ8bWFpbi10ZW5hbnQtb2lkY3xzYW1scHxTaWVtZW5zfFowMDJFSk5VIiwiZ2l2ZW5fbmFtZSI6IlJhcGhhZWwiLCJmYW1pbHlfbmFtZSI6IlNjaG5haXRsIiwibmlja25hbWUiOiJSYXBoYWVsIiwibmFtZSI6IlJhcGhhZWwgU2NobmFpdGwiLCJwaWN0dXJlIjoiaHR0cHM6Ly9zLmdyYXZhdGFyLmNvbS9hdmF0YXIvODkzNWVlY2QzMDc2ZTAyMTQ5ODE2MTZmZjBkZTRkZjI_cz00ODAmcj1wZyZkPWh0dHBzJTNBJTJGJTJGY2RuLmF1dGgwLmNvbSUyRmF2YXRhcnMlMkZyYS5wbmciLCJ1cGRhdGVkX2F0IjoiMjAxOS0xMi0wNVQxMDo0ODozMy4wNjhaIiwiZXhwIjoxNTc1NTQzMDMzLCJpc3MiOiJodHRwczovL3NpZW1lbnMtcWEtMDAwNjkuZXUuYXV0aDAuY29tLyJ9.M39aPefXmaDGzaDd0qHcQHMhvugTVN4i4pyvGJ-7fayewU9vZdtKvSzFF9rVal8GEz7HKTr_auqMw9HemOWyag==";
TokenValidationParameters tokenValidationParameters = new TokenValidationParameters
ValidIssuer = authorizationDomain,
ValidateAudience = false,
IssuerSigningKey = new ECDsaSecurityKey(ecdsa)
;
try
JwtSecurityTokenHandler jwtSecurityTokenHandler = new JwtSecurityTokenHandler();
jwtSecurityTokenHandler.ValidateToken(jwt, tokenValidationParameters, out _);
return true;
catch (SecurityTokenException)
return false;
问题是我无法测试它,因为在我的机器上(Windows 10 + .NET Core 2.1)我得到了这个错误:
System.PlatformNotSupportedException:指定的曲线“nistP256”或其参数对此平台无效。 ---> Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: 参数不正确
【讨论】:
您的代码返回 false,您是否尝试过验证我提供的令牌? ECDSA Creation 为我指明了正确的方向,但我使用充气城堡PemReader
来获取 X/Y 坐标(它们是 32 字节长,而不是 45 字节)这对我有用。
以下坐标对我有用:Q = new ECPoint X = bytes.Skip(27).Take(32).ToArray(),//ecPublicKeyParameters.Q.XCoord.GetEncoded(), Y = bytes.Skip(59).Take(32).ToArray()// ecPublicKeyParameters.Q.YCoord.GetEncoded(), );
我根据你的发现修改了答案。感谢您的反馈
在带有 .NET Core 的 Windows 10 上,如果您的 Curve 参数不正确,您将收到 PlatformNotSupportedException。以上是关于在 c# 中使用 ---PUBLIC KEY--- 验证 JWT (ES256) 令牌的主要内容,如果未能解决你的问题,请参考以下文章
在 C# 中,public、private、protected 和没有访问修饰符有啥区别?