忽略错误的证书 – .NET CORE

我正在编写一个.NET Core应用程序来轮询远程服务器并在显示时传输数据。 这在PHP中运行得很好,因为PHP忽略了证书(这也是浏览器中的一个问题),但是我们想把它转移到C#.NET CORE,因为这是系统中唯一剩下的PHP。

我们知道服务器很好,但由于各种原因,证书不能/不会很快更新。

请求是使用HttpClient:

HttpClient httpClient = new HttpClient(); try { string url = "https://URLGoesHere.php"; MyData md = new MyData(); // this is some data we need to pass as a json string postBody = JsonConvert.SerializeObject(md); httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); HttpResponseMessage wcfResponse = await httpClient.PostAsync(url, new StringContent(postBody, Encoding.UTF8, "application/json")); Console.WriteLine(wcfResponse.Content); } catch (HttpRequestException hre) { // This exception is being triggered } 

研究过这个似乎普遍的建议是使用ServicePointManager,但这在.NET Core中不可用,我在找到推荐的替代品时遇到了麻烦。

有没有一种简单或更好的方法在.NET Core中执行此操作?

而不是new HttpClient()你想要类似的东西

 var handler = new System.Net.Http.HttpClientHandler(); using (var httpClient = new System.Net.Http.HttpClient(handler)) { handler.ServerCertificateCustomValidationCallback = (request, cert, chain, errors) => { // Log it, then use the same answer it would have had if we didn't make a callback. Console.WriteLine(cert); return errors == SslPolicyErrors.None; }; ... } 

这应该适用于Windows,并且在Linux上编译libcurl以使用openssl。 使用其他curl后端Linux将引发exception。

让Linux和macOS工作

如果您使用的是Linux或macOS,则可能会遇到HttpClient不允许您访问自签名证书的情况,即使它位于您的受信任存储区中。 您可能会得到以下内容:

 System.Net.Http.CurlException: Peer certificate cannot be authenticated with given CA certificates environment variable 

如果你正在实施(如另一个答案所示)

 handler.ServerCertificateCustomValidationCallback = (request, cert, chain, errors) => { // Log it, then use the same answer it would have had if we didn't make a callback. Console.WriteLine(cert); return errors == SslPolicyErrors.None; }; 

这是因为机器上的libcurl版本不支持.Net Core需要的相应回调,以便收集适当的数据来调用ServerCertificateCustomValidationCallback 。 例如,框架没有办法创建cert对象或另一个参数。 更多信息可以在dotnet core的github repo中讨论的.NET Core中提供的变通方法的讨论中找到:

https://github.com/dotnet/corefx/issues/19709

解决方法(仅应用于测试或特定的内部应用程序)如下:

 using System; using System.Net.Http; using System.Runtime.InteropServices; namespace netcurl { class Program { static void Main(string[] args) { var url = "https://localhost:5001/.well-known/openid-configuration"; var handler = new HttpClientHandler(); using (var httpClient = new HttpClient(handler)) { // Only do this for testing and potentially on linux/mac machines if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) && IsTestUrl(url)) { handler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator; } var output = httpClient.GetStringAsync(url).Result; Console.WriteLine(output); } } static bool IsTestUrl(string url) => url.Contains("localhost"); } } 

还有另一种方法可以解决这个问题,那就是使用一个使用openssl支持编译的libcurl版本。 对于macOS,这是一个很好的教程,如何做到这一点:

https://spin.atomicobject.com/2017/09/28/net-core-osx-libcurl-openssl/

对于简短版本,请获取使用openssl支持编译的最新libcurl的副本:

 brew install curl --with-openssl 

您可能不希望强制整个操作系统使用非Apple版本的libcurl,因此您可能希望使用DYLD_LIBRARY_PATH环境变量而不是使用brew强制将二进制文件链接到操作系统的常规路径。

 export DYLD_LIBRARY_PATH=/usr/local/opt/curl/lib${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH} 

在终端中运行dotnet时,上述命令可用于设置适当的环境变量。 但这并不适用于GUI应用程序。 如果您使用的是Visual Studio for Mac,则可以在项目运行设置中设置环境变量:

Visual Studio for Mac项目运行设置

使用IdentityServer4和令牌授权时,第二种方法对我来说是必要的。 .NET Core 2.0授权管道使用HttpClient实例调用令牌权限。 由于我无法访问HttpClient或其HttpClientHandler对象,因此我需要强制HttpClient实例使用相应版本的libcurl,该版本将查看我的KeyChain系统根目录以获取我的可信证书。 否则,我将获得System.Net.Http.CurlException: Peer certificate cannot be authenticated with given CA certificates environment variable在尝试使用Authorize(AuthenticationSchemes = IdentityServerAuthenticationDefaults.AuthenticationScheme)]属性尝试保护webapi端点时, System.Net.Http.CurlException: Peer certificate cannot be authenticated with given CA certificates environment variable

在找到工作之前,我花了几个小时研究这个。 我的整个目标是在开发期间使用IdentityServer4来保护我的webapi,以便使用自签名证书。 希望这可以帮助。