尝试下载中间证书失败后,Kestrel 的 TLS 握手失败

问题描述

Kestrel 的网络服务器在加载公开签名的 SSL 证书后超时,显示连接已关闭

背景 - 我们有一个托管 dotnet 3.1 webapi/react 应用程序的 docker 容器,用户可以在其中上传自定义 SSL 证书。 PKCS#12 证书存储在我们的数据库中,并在启动时使用 .ConfigureKestrel((context,options)) 和 options.ConfigureHttpsDefaults(listenoptions=>{listenoptions.ServerCertificate = certFromDatabase; }) 绑定。这一直完美无缺。

但是,现在的问题是,用户试图在限制性防火墙环境中运行此应用程序,并在加载新证书并重新启动应用程序后立即尝试访问 Kestrel 时收到 HTTP 连接关闭错误

每当 Kestrel 收到传入请求时,它就会开始尝试通过端口 80 上的 http 从证书的 CA 公共 CDN 存储库下载中间证书。它似乎使用来自证书的授权信息访问部分的 URL。由于防火墙阻止了它,它会反复重试大约 20 秒,在此期间客户端的 TLS 握手等待服务器响应。当服务器最终无法获取中间证书时,它会取消 TLS 握手并关闭连接。

我不知道为什么它会尝试下载此证书,因为在绑定到 Kestrel 的 PKCS#12 PFX 包中嵌入了相同的证书。我是否应该将根 CA 或中间 CA 加载到文件系统中的 CA 信任文件夹中? (例如,/usr/local/share/ca-certificates/ - 我无法在那里加载中间件,只能加载 CA?)

public static IWebHost BuildFullWebHost(string[] args)
{
    var webHostBuilder = GetBaseWebHostBuilder(args);
    return webHostBuilder
        .ConfigureAppConfiguration((context,builder) => { [...] })
        .ConfigureLogging((hostingContext,logging) => { [...] })
        .UseStartup<Startup>()
        .ConfigureKestrel((context,options) =>
        {
                var sp = options.applicationservices;
                using (var scope = sp.CreateScope())
                {
                    var dbContext = scope.ServiceProvider.GetService<DbContext>();
                    var cert = Example.Services.HttpsCertificateService.GetHttpsCert(dbContext); 
                    //this returns a new X509Certificate2(certificate.HttpsCertificate,certificate.Password);
                    
                    options.ConfigureHttpsDefaults(listenoptions =>
                    {
                        listenoptions.ServerCertificate = cert;
                        listenoptions.CheckCertificateRevocation = false;
                    });
                }
        })
        .Build();
}

解决方法

不是一个很好的解决方案,但升级到 .NET 5.0 解决了这个问题。似乎在 .NET 5.0 中,Kestrel 仅在初始应用程序启动期间尝试获取证书链(并失败)。后续传入的 HTTP 请求不会触发提取过程,并且会按预期提供请求。