忽略错误证书 - .NET CORE

20

我正在编写一个 .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中有没有更简单或更好的方法来做到这一点?


2
这可能会有所帮助 https://dev59.com/EnE85IYBdhLWcg3wpFSu - Sebastian L
2
可能是bypass invalid SSL certificate in .net core的重复问题。 - thmshd
2
感谢所有指向其他线程的指针 - 但是我过去访问了它们中的所有线程,我仍然有一个问题 - 它们都无法编译。每次都会出现找不到某些引用的情况。显然,我在这里漏掉了一些明显的东西!小片段没有提供足够的信息(对我来说),例如还需要包含或引用什么其他内容。Ctrl-.也没有提供任何合理的建议。 - DaveEP
2
不要忽略证书错误,应该修复证书错误。否则,证书就没有任何意义了。 - Crypt32
2
当然,我完全同意你的看法,并已经提出了请求,但服务器不在我的控制范围内,也不是我公司拥有的,它位于一个遥远的数据中心,我只能使用我们现有的系统。这是一个即将被淘汰的遗留系统,负责维护的人员已经表示修复证书不会发生。我的任务是迁移现有数据并捕获新数据,直到它被替换。 - DaveEP
ServicePointManager在.NET Core中已经不再使用。根据https://github.com/dotnet/corefx/issues/7623,@thomashaid.com的标记重复是.NET Core中唯一支持的方式。 - Joe
4个回答

13

不要使用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上运行,以及在编译为使用openssl的libcurl的Linux上运行。对于其他curl后端,Linux会抛出异常。


3
FYI,它在Mac OS上的.NET Core 1.1中也无法工作。异常消息是:“正在使用的libcurl库(7.51.0)及其SSL后端(“SecureTransport”)不支持自定义处理证书。需要使用OpenSSL构建的libcurl。” - Ricky
@bartonjs:感谢您指出正确的方向,让我能够在macOS和可能的一些Linux版本中找出如何使其在所有情况下运作。这非常有帮助。 - Dave Ferguson
这个答案对我有用。请注意,如果您使用“cert.GetPublicKeyString();”与您期望的证书进行比较,则可以将其转换为证书固定的形式https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning以增强安全性(或至少确保您不会降低它)。 - JsAndDotNet
@bartonjs 你知道在.NET Core应用程序中如何全局忽略一个坏的证书吗? - Chris Halcrow
1
据我所知,目前还没有这样的机制(类似于ServicePoint,即使有也不是“全局”的)。 - bartonjs
显示剩余2条评论

9

让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对象或另一个参数。更多信息可以在.NET Core的GitHub存储库中的问题讨论中找到提供的解决方法。

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

您可能不想强制整个操作系统使用非苹果版本的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实例使用适当版本的libcurl,以查找我的KeyChain系统根目录中的受信任证书。否则,当尝试使用Authorize(AuthenticationSchemes = IdentityServerAuthenticationDefaults.AuthenticationScheme)属性保护webapi端点时,我会遇到System.Net.Http.CurlException:Peer certificate cannot be authenticated with given CA certificates environment variable错误。
在找到解决方法之前,我花了数小时进行研究。我整个目标是在开发过程中使用自签名证书,使用IdentityServer4来保护我的webapi。希望这有所帮助。

非常感谢您的帖子,它让我朝着正确的方向前进。我们正在使用.NET Standard 2.0,所以首先我不明白为什么会遇到所有这些问题...我已经尝试了所有与curl和openssl相关的方法,但都没有帮助我。因此,我采用了一个恶劣的hack(也无法使您的代码示例起作用)。if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { handler.ServerCertificateCustomValidationCallback = null; } - martinmose
FYI,经过花费了很多时间的努力,我将.NET Core 2.0更新到.NET Core 2.1,我的自签名证书问题消失了。我认为这与他们添加的新SocketsHandler有关,但我不确定。因此,使用HttpClient从IdentityServer4获取身份令牌和提供的Nuget包现在都可以正常工作。 - Cody

8

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

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方法。

0

只是为了增加另一种变化,您可以添加您的指纹并在回调中进行检查,以使事情更加安全,例如:

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

adminConfiguration.DevIdentityServerCertThumbprint 是你需要使用自签名证书的指纹来进行配置的设置。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接