使用 HttpClient 的“远程证书根据验证程序无效”

Posted

技术标签:

【中文标题】使用 HttpClient 的“远程证书根据验证程序无效”【英文标题】:"The remote certificate is invalid according to the validation procedure" using HttpClient 【发布时间】:2016-03-25 02:10:53 【问题描述】:

无法解决证书验证问题。

有一个 Web API 服务器,它使用 HTTPS 来处理请求。服务器的证书有这样的认证路径:RCA (root) -> ICA (intermediate) -> Web API server。 RCA、ICA 和 Web API 服务器是同一个 Active Directory 域的成员。

客户端应用(桌面、电脑加入同一个域)使用HttpClient与服务器通信,支持两种场景:

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

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

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

当客户端断开连接(只有 Internet 连接可用)时,证书验证失败并显示 AuthenticationException(“根据验证过程,远程证书无效”)。

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

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

有什么解决办法吗?

【问题讨论】:

也许当您从 Internet 连接时,Uri 主机名和证书主题之间不再匹配? 两种方案都使用相同的连接字符串:“host.domain.zone”。证书科目有:1)RCA:“RCA, domain, zone”; 2)ICA:“ICA1,域,区域”; 3) Web 服务器:“HOST.domain.zone”。我不知道,不同的主题格式是否起作用...... 也许您可以发布您网站的公共 URL 以便我们查看? 另外,如果我尝试通过 IE 连接 Web API,我会收到以下消息:“此网站提供的安全证书是为不同网站的地址颁发的”。 “该网站提供的安全证书是针对不同网站的地址签发的”基本上就是我在第一条评论中所说的。 【参考方案1】:

您遇到的问题是因为证书提供的主题 CN 与 Uri 中的主机名不匹配。

确保绑定到主机公共 IP 地址的证书确实具有与您用于访问资源的主机名匹配的 CN。

要轻松验证,请在浏览器中打开 URL 并查看证书。 Issued to 字段应包含 FQDN 并与 Uri 中的主机名部分匹配。在你的情况下,它没有。

【讨论】:

【参考方案2】:

在程序主体上插入这段代码:

static void Main(string[] args)   

     ServicePointManager.ServerCertificateValidationCallback =
                delegate (object sender, X509Certificate certificate, X509Chain 
     chain, SslPolicyErrors sslPolicyErrors)
                
                    return true;
                ;
     ....

【讨论】:

当我需要测试提供自签名开发证书的 api 时,这对我在开发环境中运行时有用。 这实际上完全禁用了证书验证。强烈不推荐。 另外,使用客户端证书时不会触发回调。见:github.com/dotnet/corefx/issues/17226 这对于在单元或 SIT 测试 Web 服务时使用自签名证书非常方便。需要注意的是,它并没有禁用身份验证,它只是禁用了证书的客户端验证。 显然不推荐用于生产代码,但非常推荐用于概念证明或单元测试。必须为特定证书编写解决方法将需要构建该基础设施,然后无论如何这些基础设施将被完全丢弃在生产代码中。所以我相信这个解决方案对于这种特殊情况是有好处的。【参考方案3】:

不幸的是,@Qosai 的答案对我来说还不够,至少在 SignalR 3.1 客户端中,因为 websocket 部分也验证 SSL 证书。 ClientCertificateOptions 也需要设置为手动。

我发现 SignalR 贡献者的 post 让我工作:

_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:如果您仍有问题,请查看article,了解如何正确启用日志记录。就我而言,这有点棘手,因为 xUnit 不显示控制台输出。因此,我启用了调试日志记录到文件(不在 sn-p 中)

【讨论】:

以上是关于使用 HttpClient 的“远程证书根据验证程序无效”的主要内容,如果未能解决你的问题,请参考以下文章

HttpClient学习整理

HttpClient介绍和简单使用流程

HttpClient使用笔记

HttpClient使用详解

处理注入的 HttpClient

释放 HttpClient 4.1.x 的连接以使用一个 HttpClient 实例顺序执行