为何ASP.NET Core Kestrel加载自签名根证书后仍需存入受信任根证书存储?
问题
我有一个基于ASP.NET Core 6与Kestrel Web Server的应用,要求客户端与服务器之间采用mTLS通信。我通过PowerShell的New-SelfSignedCertificate cmdlet生成了自签名根证书及客户端子证书,并通过以下代码将根证书显式加载到Kestrel:
var rootCertFile ="xxx.pfx"; var rootCertPw = "abc"; X509Certificate2 rootCert = new X509Certificate2( rootCertFile, rootCertPw); webBuilder.ConfigureKestrel(o => { o.ConfigureHttpsDefaults(o => { o.ServerCertificate = rootCert; o.ClientCertificateMode = ClientCertificateMode.RequireCertificate; }); }); webBuilder.UseKestrel(o => { o.Listen(IPAddress.Parse(myHttpsEndPointIpAddr), myHttpsEndPointPort, listenOptions => { listenOptions.UseHttps(); }); o.Listen(IPAddress.Parse(myHttpEndPointIpAddr), myHttpEndPointPort); });
当客户端(如curl或Postman)使用由该根证书签名的子证书调用HTTPS端点时,若根证书未存入本地机器的Trusted Root Certification Authorities Certificate Store,客户端会收到错误并被拒绝调用,错误信息如下:
* TLSv1.2 (IN), TLS header, Unknown (21): * TLSv1.2 (IN), TLS alert, unknown CA (560): * OpenSSL SSL_read: error:0A000418:SSL routines::tlsv1 alert unknown ca, errno 0 * Failed receiving HTTP2 data * OpenSSL SSL_write: SSL_ERROR_ZERO_RETURN, errno 0 * Failed sending HTTP2 data
一旦将根证书添加到本地机器的Trusted Root Certification Authorities Certificate Store,API调用即可成功。请问为何Kestrel已直接加载自签名根证书,仍需将其安装到受信任根证书存储中?
回答
核心原因是你搞反了验证方向:
- 你在Kestrel里设置的
ServerCertificate是服务器用来向客户端证明自己身份的证书,而mTLS里客户端验证服务器身份的逻辑是客户端本地完成的,和Kestrel有没有加载根证书完全没关系。 - 客户端发起HTTPS请求时,会先校验服务器证书的合法性:你的服务器证书由自签名根CA签发,但客户端默认只信任系统预装的公共根CA,根本不认可你这个自定义的根CA,所以会抛出"unknown CA"错误。
- 把根证书加到客户端机器的受信任根存储,本质是告诉客户端:这个根CA是可信的,由它签发的服务器证书可以放心信任。
另外补充一点:你当前的Kestrel配置其实没完成mTLS的完整验证——你只要求客户端提供证书,但没配置Kestrel去验证客户端证书是否由可信根CA签发。正确做法是在ConfigureHttpsDefaults里添加客户端证书验证逻辑,指定信任的根CA,示例代码如下:
o.ClientCertificateValidation = (cert, chain, errors) => { // 验证客户端证书是否由指定的根CA签发 return chain.ChainElements.Cast<X509ChainElement>() .Any(element => element.Certificate.Thumbprint == rootCert.Thumbprint) && errors == SslPolicyErrors.None; };
这样Kestrel才会真正校验客户端证书的合法性,而不是只要求客户端提供证书就行。
内容的提问来源于stack exchange,提问作者RickyTad
相关产品推荐
相关产品推荐

