使用HttpClient时出现“远程证书根据验证程序无效”的错误

22

无法通过证书验证解决问题。

存在 Web API 服务器,使用 HTTPS 处理请求。服务器的证书具有此认证路径:RCA(根)-> ICA(中间)-> Web API 服务器。 RCA、ICA 和 Web API 服务器都是同一 Active Directory 域的成员。

客户端应用程序(桌面计算机加入了相同的域),使用 HttpClient 与服务器通信,并支持两种情况:

  • 连接到公司网络;
  • 断开公司网络连接(访问互联网)。

这两种情况均使用基本身份验证。
RCA 和 ICA 证书分别放置在本地计算机帐户的“受信任的根证书颁发机构”和“中间证书颁发机构”中。 RCA 证书为自签名证书。

现在,当客户端连接到公司网络时,证书验证按预期工作,用户可以“交谈”Web API。

当客户端断开连接(仅可用互联网连接)时,证书验证失败并出现AuthenticationException( “根据验证过程,远程证书无效”)。

我不想完全关闭证书验证,但只需要一种方法来告诉验证系统,该特定证书有效。 此外,客户端应用程序使用 SignalR,默认使用其自己的传输。因此,thisthis 不是选项。

为什么将 RCA 和 ICA 证书放置在“受信任...”和“中间...”文件夹中没有帮助?

是否有任何解决方法?


也许当您从互联网连接时,Uri主机名和证书主题之间不再匹配? - Mihai Caracostea
两种情况都使用相同的连接字符串:"https://host.domain.zone"。证书主体分别是:1)RCA:"RCA, domain, zone";2)ICA:"ICA1, domain, zone";3)Web服务器:"HOST.domain.zone"。我不知道,主体的格式是否起到了作用... - Dennis
也许你可以发布你的网站公共URL,这样我们就可以查看它了? - Mihai Caracostea
另外,如果我尝试通过IE连接Web API,我会收到以下消息:“此网站呈现的安全证书是为不同网站的地址颁发的”。 - Dennis
让我们在聊天中继续这个讨论 - Mihai Caracostea
显示剩余2条评论
3个回答

17
您遇到的问题是由于证书提供的主题CN与Uri中主机名不匹配所致。
请确保绑定到主机的公共IP地址的证书具有与您用于访问资源的主机名匹配的CN。
为了轻松验证,请在浏览器中打开网址并查看证书。"Issued to"字段应包含FQDN并匹配Uri中的主机名部分。在您的情况下,它不匹配。

通配符证书是否会成为问题?在我的情况下(一个Azure DevOps 2020服务器),它们确实匹配,但我仍然收到此错误。 - tnk479

16

请将以下代码插入到程序主体中:

static void Main(string[] args)   
{
     ServicePointManager.ServerCertificateValidationCallback =
                delegate (object sender, X509Certificate certificate, X509Chain 
     chain, SslPolicyErrors sslPolicyErrors)
                {
                    return true;
                };
     ....
}

当我需要测试一个提供自签名开发证书的API时,这对我在开发环境中运行时有效。 - Nathan Fisher
16
这实际上完全禁用了证书验证。强烈不建议这样做。 - Mihai Caracostea
此外,在使用客户端证书时,回调函数不会被触发。请参见:https://github.com/dotnet/corefx/issues/17226 - Jari Turkia
这对于在单元测试或SIT测试Web服务时使用自签名证书非常方便。需要注意的是,它并不禁用身份验证,只是禁用了客户端对证书的验证。 - rrreee
1
显然不建议用于生产代码,但非常推荐用于概念证明或单元测试。为特定证书编写解决方案需要构建基础设施,而这些基础设施在生产代码中将被完全废弃。因此,我相信这种解决方案对于特定情况是有价值的。 - AsPas

9

@Qosai的答案对我来说不够充分,至少在SignalR 3.1客户端中,websocket部分也会验证SSL证书。必须将ClientCertificateOptions设置为手动模式。

我发现了一篇由SignalR贡献者发布的帖子,使我得以正常工作:

_connection = new HubConnectionBuilder()
            .WithUrl(new Uri(hub_uri), options => {
                options
                    .Cookies
                    .Add(http_helper.loginCookie);

                var handler = new HttpClientHandler
                {
                    ClientCertificateOptions = ClientCertificateOption.Manual,
                    ServerCertificateCustomValidationCallback = (httpRequestMessage, cert, cetChain, policyErrors) => true
                };
                options.HttpMessageHandlerFactory = _ => handler;
                options.WebSocketConfiguration = sockets =>
                {
                    sockets.RemoteCertificateValidationCallback = (sender, certificate, chain, policyErrors) => true;
                };
            })
            .Build();

PS: 如果你仍然有问题,请查看此文章以了解如何正确启用日志记录。在我的情况下,有点棘手,因为xUnit不显示控制台输出。因此,我将调试日志记录到文件中进行了启用(未在代码片段中显示)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接