2017-03-10 113 views
9

我正在编写一个.NET Core应用程序来轮询远程服务器并在数据出现时进行传输。这在PHP中是完美的,因为PHP忽略了证书(这在浏览器中也是一个问题),但我们希望将它移到C#.NET CORE中,因为这是系统中唯一剩余的PHP。忽略坏证书 - .NET CORE

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

的请求正在使用的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中提供的核心,我无法找到建议更换。

有没有一个简单的或更好的方法在.NET Core中做到这一点?

+2

这可能是有用的http://stackoverflow.com/questions/2675133/c-sharp-ignore-certificate-errors –

+2

可能重复的[绕过无效SSL证书在.net核心](http://stackoverflow.com/questions/38138952/bypass-invalid-ssl-certificate-in-net-core) – thmshd

+2

感谢所有指向其他线程的指针 - 但在过去曾经访问过它们,但仍然有问题 - 它们都不会编译。每次都有一些无法找到的参考。很明显,我错过了一些明显的东西!小片段没有提供足够的信息(对我来说),比如还需要包含或引用其他信息。按Ctrl - 。也没有提出任何合理的建议。 – DaveEP

回答

5

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

+2

仅供参考,它在Mac OS上的.NET Core 1.1中也不起作用。异常消息是:'正在使用的libcurl库(7.51.0)及其SSL后端(“SecureTransport”)不支持自定义处理证书。一个使用OpenSSL构建的libcurl是必需的。)' – Ricky

+0

Ricky,请参阅我的上述答案以获得一些选项。 –

+0

@bartonjs:感谢您指出我正确的方向,以了解如何在macos和可能的某些Linux版本的所有场景中实现这一功能。这非常有帮助。 –

2

获取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核心需要为了收集适当的数据来调用ServerCertificateCustomValidationCallback。例如,框架无法创建cert对象或另一个参数。更多信息,请以.Net核心的问题DOTNET核心的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"); 
    } 
} 

没有为解决这个问题的另一个途径,那就是使用的libcurl的一个版本,与OpenSSL的支持编译。适用于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来强制将二进制文件链接到OS的常规路径。

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

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

Visual Studio for Mac project run settings

第二种方法是必要的我。 .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为macOs开发期间使用自签名证书来保护我的webapi。希望这可以帮助。

+0

非常感谢您的信息。它帮助我朝着正确的方向前进。 我们正在使用.NET标准2。0所以首先我不明白为什么我面临所有这些问题... 我已经尝试了一切与卷曲和openssl和那些东西,没有什么帮助我。 所以我去了一个讨厌的黑客(不能让你的代码示例既不工作)。 'if(RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) handler.ServerCertificateCustomValidationCallback = null; }' – martinmose