.NET 8 ASP.NET API证书认证失败:签名无法验证求助
我正在开发基于.NET 8的ASP.NET应用,其API接口采用证书认证。测试环境中使用自签名证书或PKI证书时认证正常,但生产客户端调用作为域测试环境的Kestrel开发服务器时,触发OnAuthenticationFailed,错误日志如下:
Microsoft.AspNetCore.Authentication.Certificate.CertificateAuthenticationHandler[2] Certificate validation failed, subject was CN=PC1.contoso.com. NotSignatureValid The signature of the certificate cannot be verified. Microsoft.AspNetCore.Authentication.Certificate.CertificateAuthenticationHandler: Warning: Certificate validation failed, subject was CN=PC1.contoso.com. NotSignatureValid The signature of the certificate cannot be verified.
我的证书认证配置代码如下:
.AddCertificate(CertificateAuthenticationDefaults.AuthenticationScheme, options => { options.RevocationMode = X509RevocationMode.NoCheck; options.AllowedCertificateTypes = CertificateTypes.All; var cer = builder.Configuration.GetSection("Certificate").GetSection("Root").GetValue<string>("TrustStore"); var cer_int = "Resource\Sub CA.cer"; var cer_root = "Resource\Root CA.cer"; //options.CustomTrustStore.AddRange(new X509Certificate2Collection {new X509Certificate2(Path.Combine(cer_root))}); options.CustomTrustStore.Add(new X509Certificate2(Path.Combine(cer_root))); options.CustomTrustStore.Add(new X509Certificate2(Path.Combine(cer_int))); options.ChainTrustValidationMode = X509ChainTrustMode.CustomRootTrust;
Kestrel配置如下:
builder.Services.Configure<KestrelServerOptions>(options => { options.ConfigureHttpsDefaults(options => { options.AllowAnyClientCertificate(); options.CheckCertificateRevocation = false; options.ClientCertificateMode = ClientCertificateMode.DelayCertificate; }); });
我已尝试将生产环境的根证书和中级证书添加到CustomTrustStore,甚至导入本地证书存储。该应用最终将部署为Azure Web App,因此用Kestrel测试(暂不知Azure调试方法),且客户端在Kestrel和Azure中的反应类似。请问为何证书会被拒绝?
针对NotSignatureValid错误,可从以下几个方向逐一排查:
1. 修复证书路径解析问题
代码中证书路径使用了反斜杠\,在C#字符串中反斜杠是转义字符,若未使用@前缀或转义为\\,会导致路径解析错误,证书无法正确加载到CustomTrustStore中。
解决方法:
将路径改为带@的逐字字符串,或使用正斜杠:
var cer_int = @"Resource\Sub CA.cer"; var cer_root = @"Resource\Root CA.cer"; // 或 var cer_int = "Resource/Sub CA.cer"; var cer_root = "Resource/Root CA.cer";
同时可添加日志验证证书是否成功加载:
var rootCert = new X509Certificate2(Path.Combine(cer_root)); var intCert = new X509Certificate2(Path.Combine(cer_int)); // 添加日志确认证书信息 logger.LogInformation("Root CA loaded: {Subject}", rootCert.Subject); logger.LogInformation("Sub CA loaded: {Subject}", intCert.Subject); options.CustomTrustStore.Add(rootCert); options.CustomTrustStore.Add(intCert);
2. 验证证书链的签名关系
即使加载了根和中级证书,需确保客户端证书的签名链完整:
- 客户端证书必须由配置的中级CA签发
- 中级CA证书必须由配置的根CA签发
- 检查证书的颁发者与主题是否匹配:中级CA的主题应等于客户端证书的颁发者,根CA的主题应等于中级CA的颁发者
验证方法:
双击客户端证书,查看「证书路径」标签,确认链中所有证书都已正确添加到CustomTrustStore,无缺失环节。
3. 完善CustomRootTrust的链验证逻辑
.NET 8中使用CustomRootTrust时,链验证仅信任CustomTrustStore中的根证书,不会自动包含系统信任存储。需确保:
- 中级CA证书已显式添加到
CustomTrustStore - 中级CA证书的签名由根CA签发,且根CA在
CustomTrustStore中
4. 调整证书加载的存储标志
加载.cer证书时,可指定X509KeyStorageFlags避免权限问题导致验证失败:
var rootCert = new X509Certificate2(Path.Combine(cer_root), "", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet); var intCert = new X509Certificate2(Path.Combine(cer_int), "", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);
5. 手动构建证书链调试
在认证中间件中添加自定义验证逻辑,输出链验证的具体失败信息:
options.Events = new CertificateAuthenticationEvents { OnCertificateValidated = context => { var chain = new X509Chain(); chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; chain.ChainPolicy.CustomTrustStore.AddRange(options.CustomTrustStore); chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust; bool isValid = chain.Build(context.ClientCertificate); if (!isValid) { foreach (var status in chain.ChainStatus) { context.Logger.LogError("Chain validation failed: {Status} - {Info}", status.Status, status.StatusInformation); } context.Fail("Certificate chain validation failed"); } return Task.CompletedTask; } };
6. Azure Web App环境的特殊配置
若部署到Azure Web App,需额外注意:
- 将根证书和中级证书上传到Azure「TLS/SSL设置」的「证书」模块,或确保证书文件包含在应用程序包中
- 在Azure Web App配置中启用「客户端证书模式」为「需要」或「可选」
- 用
Path.GetFullPath(cer_root)输出实际路径到日志,验证路径是否正确
内容的提问来源于stack exchange,提问作者Stephan

