C# 忽略错误的证书-.NET CORE

C# 忽略错误的证书-.NET CORE,c#,.net,ssl-certificate,.net-core,ignore,C#,.net,Ssl Certificate,.net Core,Ignore,我正在编写一个.NETCore应用程序,用于轮询远程服务器并按显示方式传输数据。这在PHP中工作得很好,因为PHP忽略了证书(这在浏览器中也是一个问题),但我们希望将其移动到C#.NET核心,因为这是系统中仅存的PHP 我们知道服务器很好,但是由于各种原因,证书不能/不会很快更新 请求正在使用HttpClient: HttpClient httpClient = new HttpClient(); try { string

我正在编写一个.NETCore应用程序,用于轮询远程服务器并按显示方式传输数据。这在PHP中工作得很好,因为PHP忽略了证书(这在浏览器中也是一个问题),但我们希望将其移动到C#.NET核心,因为这是系统中仅存的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中有没有一种简单或更好的方法来实现这一点?

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

让Linux和macOS正常工作

如果您在Linux或macOS中工作,您可能会遇到这样一种情况,
HttpClient
将不允许您访问自签名证书,即使它位于您的受信任存储中。您可能会得到以下结果:

System.Net.Http.CurlException: Peer certificate cannot be authenticated with given CA certificates environment variable
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");
    }
}
如果您正在实施(如另一个答案所示)

这是因为计算机上的libcurl版本不支持.Net Core收集调用
服务器CertificateCustomValidationCallback所需的适当回调。例如,框架无法创建
cert
对象或另一个参数。有关dotnet Core的github repo中有争议的.NET Core中提供的解决方案的讨论中可以找到更多信息:

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

System.Net.Http.CurlException: Peer certificate cannot be authenticated with given CA certificates environment variable
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");
    }
}
还有另一种方法可以解决这个问题,那就是使用一个版本的libcurl,该版本是使用openssl支持编译的。对于macOS,这里有一个很好的教程,介绍如何做到这一点:

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

brew install curl --with-openssl
您可能不想强制整个操作系统使用非苹果版本的libcurl,因此您可能希望使用
DYLD\u LIBRARY\u PATH
环境变量,而不是使用brew强制将二进制文件链接到操作系统的常规路径

export DYLD_LIBRARY_PATH=/usr/local/opt/curl/lib${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH}
在终端中运行
dotnet
时,可以使用上述命令设置适当的环境变量。但这并不真正适用于GUI应用程序。如果您使用的是Visual Studio for Mac,则可以在项目运行设置中设置环境变量:

在使用IdentityServer4和令牌授权时,第二种方法对我来说是必要的。.NET Core 2.0授权管道正在使用
HttpClient
实例调用令牌授权机构。由于我没有访问
HttpClient
或其
HttpClientHandler
对象的权限,我需要强制
HttpClient
实例使用适当版本的libcurl,该版本将查找我的密钥链系统根以获取我的可信证书。否则,当尝试使用
授权(AuthenticationSchemes=IdentityServerAuthenticationDefaults.AuthenticationScheme)]
属性保护webapi终结点时,我将获得
System.Net.Http.CurlException:无法使用给定的CA certificates环境变量对对等证书进行身份验证


在找到工作之前,我花了几个小时研究这个问题。我的全部目标是在开发macOs时使用自签名证书,使用IdentityServer4保护我的webapi。希望这有帮助。

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

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方法来添加另一个变体,您可以添加指纹并在回调中检查它,使事情更加安全,例如:

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

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

这可能会很有帮助,感谢所有指向其他线程的指针-但在过去访问过所有线程后,我仍然有一个问题-它们都不会编译。每次都有一些无法找到的参考资料。很明显我错过了一些明显的东西!这些小片段没有提供足够的信息(给我),比如需要包含或引用的其他信息。Ctrl-。也没有提出任何合理的建议。您应该修复证书错误,而不是忽略证书错误。当然,我百分之百同意你的要求,但是服务器不在我的控制之下,也不属于我的公司,它在一个很远的数据中心里,我一直在坚持我们所拥有的。这是一个遗留系统,很快就会被淘汰,负责维护的人员表示不会修复证书。我的任务是迁移现有数据并捕获新数据,直到数据被替换。仅供参考,它在Mac OS上的.NET Core 1.1中也不起作用。异常消息是:
正在使用的libcurl库(7.51.0)及其SSL后端(“SecureTransport”)不支持证书的自定义处理。需要一个用OpenSSL构建的libcurl。)
Ricky,请参阅我上面的答案,以获得几个选项。@bartonjs:感谢你为我指明了正确的方向,让我知道如何在macos上的所有场景中以及可能的某些Linux版本中都能使用它。这很有帮助。这个答案对我很有用。注意,如果使用“cert.GetPublicKeyString();”要与预期的证书进行比较,您可以将其转换为一种证书固定形式,以增强安全性(或至少确保不会降低其级别)。@ChrisH