忽略错误的证书 - .NET CORE

时间:2017-03-10 07:38:42

标签: c# .net ssl-certificate .net-core ignore

我正在编写.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中有一种简单或更好的方法吗?

4 个答案:

答案 0 :(得分:10)

而不是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将抛出异常。

答案 1 :(得分:5)

让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 project run settings

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

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

答案 2 :(得分:0)

//在启动配置服务时添加以下代码

services.AddHttpClient(settings.HttpClientName, client => {
// code to configure headers etc..
}).ConfigurePrimaryHttpMessageHandler(() => {
                  var handler = new HttpClientHandler();
                  if (hostingEnvironment.IsDevelopment())
                  {
                      handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return true; };
                  }
                  return handler;
              });

现在您可以在服务中使用IHttpClientFactory CreateClient方法

答案 3 :(得分:0)

只需添加另一个变体,您就可以添加指纹并在回调中进行检查,以使事情更加安全,例如:

if (!string.IsNullOrEmpty(adminConfiguration.DevIdentityServerCertThumbprint))
{
   options.BackchannelHttpHandler = new HttpClientHandler
   {
      ServerCertificateCustomValidationCallback = (sender, certificate, chain, sslPolicyErrors) => certificate.Thumbprint.Equals(adminConfiguration.DevIdentityServerCertThumbprint, StringComparison.InvariantCultureIgnoreCase)
   };
}

adminConfiguration.DevIdentityServerCertThumbprint是您将使用自签名证书的指纹设置的配置。