简体   繁体   English

忽略错误证书 - .NET CORE

[英]Ignore bad certificate - .NET CORE

I'm writing a .NET Core app to poll a remote server and transfer data as it appears.我正在编写一个 .NET Core 应用程序来轮询远程服务器并在出现数据时传输数据。 This is working perfectly in PHP because the PHP is ignoring the certificate (which is also a problem in browsers) but we want to move this to C# .NET CORE because this is the only remaining PHP in the system.这在 PHP 中运行良好,因为 PHP 忽略了证书(这也是浏览器中的一个问题),但我们希望将其移至 C# .NET CORE,因为这是系统中唯一剩余的 PHP。

We know the server is good, but for various reasons the certificate can't / won't be updated any time soon.我们知道服务器很好,但由于各种原因,证书不能/不会很快更新。

The request is using HttpClient:该请求正在使用 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
        }

Having researched this it seems the universal recommendation is to use ServicePointManager, but this is not available in .NET Core and I'm having trouble finding the recommended replacement.对此进行研究后,似乎普遍建议使用 ServicePointManager,但这在 .NET Core 中不可用,我无法找到推荐的替代品。

Is there a simple or better way to do this in .NET Core?在 .NET Core 中是否有简单或更好的方法来做到这一点?

Instead of new HttpClient() you want something akin to而不是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;
    };

    ...
}

That should work on Windows, and on Linux where libcurl is compiled to use openssl.这应该适用于 Windows 和 Linux,其中 libcurl 被编译为使用 openssl。 With other curl backends Linux will throw an exception.对于其他 curl 后端,Linux 会抛出异常。

//at startup configure services add the following code //在启动配置服务时添加以下代码

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;
              });

now you can use IHttpClientFactory CreateClient method within your service现在您可以在您的服务中使用 IHttpClientFactory CreateClient 方法

Getting Linux and macOS to work让 Linux 和 macOS 正常工作

If you are working in Linux or macOS you may encounter a scenario in which HttpClient will not allow you to access a self signed cert even if it is in your trusted store.如果您在 Linux 或 macOS 中工作,您可能会遇到HttpClient不允许您访问自签名证书的情况,即使它在您受信任的存储中。 You will likely get the following:您可能会得到以下信息:

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

of if you are implementing (as shown in the other answer)如果您正在实施(如另一个答案所示)

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;
};

This is due to the version of libcurl on the machine not supporting the appropriate callbacks that .Net Core needs to in order to gather the appropriate data to call the ServerCertificateCustomValidationCallback .这是因为机器上的 libcurl 版本不支持 .Net Core 需要的适当回调,以便收集适当的数据以调用ServerCertificateCustomValidationCallback For example, there isn't a way for the framework to create the cert object or another one of the parameters.例如,框架没有办法创建cert对象或另一个参数。 More information can be found in the discussion for the workaround that was provided in .NET Core at issue in dotnet core's github repo:更多信息可以在 .NET Core 中提供的解决方法的讨论中找到,在 dotnet core 的 github repo 中有问题:

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

The workaround (which should only be used for testing or specific internal applications) is the following:解决方法(应仅用于测试或特定的内部应用程序)如下:

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");
    }
}

There is another avenue for fixing this problem, and that is using a version of libcurl that is compiled with openssl support.还有另一种解决此问题的方法,那就是使用支持 openssl 的 libcurl 版本。 For macOS, here is a good tutorial on how to do that:对于 macOS,这里有一个关于如何做到这一点的好教程:

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

For the short version, grab a copy of the latest libcurl compiled with openssl support:对于简短版本,获取支持 openssl 的最新 libcurl 的副本:

brew install curl --with-openssl

You probably don't want to force the entire OS to use the non-Apple version of libcurl, so you'll likely want to use the DYLD_LIBRARY_PATH environment variable instead of using brew to force link the binaries into the regular path of the OS.您可能不想强制整个操作系统使用非 Apple 版本的 libcurl,因此您可能希望使用DYLD_LIBRARY_PATH环境变量而不是使用 brew 强制将二进制文件链接到操作系统的常规路径。

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

The above command can be used to set the appropriate environment variable when running dotnet in a terminal.上述命令可用于在终端中运行dotnet时设置适当的环境变量。 This doesn't really apply to GUI applications though.但这并不真正适用于 GUI 应用程序。 If you're using Visual Studio for Mac, you can set the environment variable in the project run settings:如果您使用的是 Visual Studio for Mac,则可以在项目运行设置中设置环境变量:

Visual Studio for Mac 项目运行设置

The second approach was necessary for me when using IdentityServer4 and token authorization.在使用 IdentityServer4 和令牌授权时,第二种方法对我来说是必要的。 The .NET Core 2.0 authorization pipeline was making a call to the token authority using an HttpClient instance. .NET Core 2.0 授权管道正在使用HttpClient实例调用令牌授权。 Since I didn't have access to the HttpClient or its HttpClientHandler object, I needed to force the HttpClient instance to use the appropriate version of libcurl that would look into my KeyChain system roots for my trusted certificate.由于我无权访问HttpClient或其HttpClientHandler对象,因此我需要强制HttpClient实例使用合适的 libcurl 版本,以便查看我的 KeyChain 系统根目录以获得我的受信任证书。 Otherwise, I would get the System.Net.Http.CurlException: Peer certificate cannot be authenticated with given CA certificates environment variable when trying to secure a webapi endpoint using the Authorize(AuthenticationSchemes = IdentityServerAuthenticationDefaults.AuthenticationScheme)] attribute.否则,在尝试使用Authorize(AuthenticationSchemes = IdentityServerAuthenticationDefaults.AuthenticationScheme)]属性保护 webapi 端点时,我会得到System.Net.Http.CurlException: Peer certificate cannot be authenticated with given CA certificates environment variable

I spent hours researching this before finding work arounds.在找到解决方法之前,我花了几个小时研究这个。 My whole goal was to use a self-signed certificate during development for macOs using IdentityServer4 to secure my webapi.我的整个目标是在使用 IdentityServer4 的 macO 开发过程中使用自签名证书来保护我的 webapi。 Hope this helps.希望这可以帮助。

Just to add another variation, you could add in your thumbprint and check it in the callback to make things a bit more secure such as:只是为了添加另一个变体,您可以添加指纹并在回调中检查它以使事情更安全,例如:

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

adminConfiguration.DevIdentityServerCertThumbprint is the configuration that you would set with your self signed cert's thumbrint. adminConfiguration.DevIdentityServerCertThumbprint是您将使用自签名证书的指纹设置的配置。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM