.NET Core API:无需共享公钥的非对称JWT密钥生成方案
可行方案:基于公钥哈希注册的客户端自签名JWT验证
完全可以实现这种需求,核心思路是让客户端自行生成非对称密钥对,服务端仅预存客户端公钥的唯一哈希标识而非公钥本身,验证时通过提取请求中的公钥并校验哈希合法性,再完成签名验证。具体方案如下:
核心流程
- 客户端按指定规范生成非对称密钥对(比如RS256算法、2048位密钥)
- 客户端计算自身公钥的SHA-256哈希,通过内部安全流程提交给服务端完成注册(服务端将哈希存入信任列表)
- 客户端每次请求时,在JWT的
x5c(X.509证书链)头部字段携带自己的公钥 - 服务端先提取公钥计算哈希,匹配信任列表中的合法哈希,验证通过后再用该公钥校验JWT签名
.NET Core 实现要点
存储信任的公钥哈希
可以用配置文件或数据库维护信任列表,示例配置:"TrustedClients": { "PubKeyHashes": [ "a1b2c3d4e5f6...", "f6e5d4c3b2a1..." ] }自定义JWT验证逻辑
在认证中间件中添加哈希校验步骤,示例代码片段:services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = false, // 根据内部需求调整 ValidateAudience = false, ValidateLifetime = true, SignatureValidator = (token, parameters) => { var jwtHandler = new JwtSecurityTokenHandler(); var jwtToken = jwtHandler.ReadJwtToken(token); // 从头部提取x5c字段中的公钥 var x5c = jwtToken.Header.TryGetValue("x5c", out var value) ? value as List<string> : null; if (x5c == null || x5c.Count == 0) throw new SecurityTokenInvalidSignatureException("Missing public key in header"); // 解析公钥 var pubKeyBytes = Convert.FromBase64String(x5c[0]); var pubKey = new X509Certificate2(pubKeyBytes).GetRSAPublicKey(); // 计算公钥哈希 var pubKeyHash = SHA256.HashData(pubKey.ExportSubjectPublicKeyInfo()); var pubKeyHashHex = BitConverter.ToString(pubKeyHash).Replace("-", "").ToLower(); // 校验哈希是否在信任列表 var trustedHashes = Configuration.GetSection("TrustedClients:PubKeyHashes").Get<List<string>>(); if (!trustedHashes.Contains(pubKeyHashHex)) throw new SecurityTokenInvalidSignatureException("Untrusted public key"); // 验证签名 var validationParameters = new TokenValidationParameters { IssuerSigningKey = new RsaSecurityKey(pubKey), ValidateIssuerSigningKey = true }; jwtHandler.ValidateToken(token, validationParameters, out var validatedToken); return validatedToken as JwtSecurityToken; } }; });客户端密钥生成规范
给客户端明确以下要求:- 必须使用RS256算法生成非对称密钥对,密钥长度不低于2048位(推荐4096位)
- 公钥需封装为X.509证书(或直接导出SPKI格式),转为Base64后放入JWT的
x5c头部数组的第一个元素 - 计算公钥哈希时,需导出公钥的SPKI格式字节流,再用SHA-256哈希,结果转为小写十六进制字符串提交注册
注意事项
- 公钥哈希的注册必须通过内部安全审批流程,确保只有合法客户端能加入信任列表
- 客户端需严格保管私钥,一旦泄露需立即生成新密钥对并重新注册哈希
- 服务端可定期清理过期或停用的客户端哈希,减少验证开销
内容的提问来源于stack exchange,提问作者Ramki
相关产品推荐
相关产品推荐

