使用Httpclient信任自签名证书

时间:2017-12-05 23:11:43

标签: c# xamarin xamarin.ios dotnet-httpclient

我试图提出因自签名证书而失败的网络请求:

Client = new HttpClient(); 
HttpResponseMessage Response = await Client.GetAsync(Uri)//defined elsewhere 

这会引发信任失败异常。

我按照Allowing Untrusted SSL Certificates with HttpClient建议使用httpclienthandler再次尝试:

 var handler = new HttpClientHandler();

 handler.ServerCertificateCustomValidationCallback = 
 (
   HttpRequestMessage message, 
   X509Certificate2 cert, 
   X509Chain chain, 
   SslPolicyErrors errors
  ) =>{return true; };//remove if this makes it to production 

  Client = new HttpClient(handler); 

这会引发一个没有实现例外的系统。

还有其他方法可以信任自签名证书吗?我甚至在提出请求的机器上安装了证书,但没有运气。

1 个答案:

答案 0 :(得分:6)

我已经看到很多这方面的问题,我想我尽可能地写完了答案和例子。

注意:将WKWebView与自签名证书一起使用,请参阅此answer

HttpClient实现

注意:在此示例中使用badssl.com

管理(默认)

  

System.Net.Http.HttpRequestException:发送请求时发生错误--->   System.Net.WebException:错误:TrustFailure(发生一个或多个错误。)--->   System.AggregateException:发生一个或多个错误。 --->   System.Security.Authentication.AuthenticationException:对SSPI的调用失败,请参阅内部异常。 --->   Mono.Security.Interface.Tl

原始的Mono Managed提供商在安全性和安全性方面仅支持 长期支持TLS1.0。性能我将转向使用NSUrlSession实现。

CFNetwork(iOS 6 +)

注意:由于这个iOS版本现在已经很老了,我个人不再瞄准它了,所以我把它留空......(除非有人真的需要我为它查找我的笔记; - )

NSUrlSession(iOS 7 +)

Xamarin提供基于iOS“HttpMessageHandler的{​​{1}}子类(NSUrlSessionHandler)。

单独使用它来对付自签名证书将导致:

  

System.Net.WebException:发生SSL错误,无法与服务器建立安全连接。 --->   Foundation.NSErrorException:   抛出了类型'Foundation.NSErrorException'的异常。

问题在于,自签名证书被iOS视为不安全且不受信任,因此您必须将ATS例外应用于您的应用,以便iOS知道您的应用在NSUrlSession中不受信任。< / p>

Info.plist

现在iOS知道您的应用正在进行不受信任的呼叫,<key>NSAppTransportSecurity</key> <dict> <key>NSExceptionDomains</key> <dict> <key>self-signed.badssl.com</key> <dict> <key>NSExceptionAllowsInsecureHTTPLoads</key> <true/> </dict> </dict> </dict> 请求现在会导致此错误:

  

System.Net.WebException:此服务器的证书无效。您可能正在连接到假装为self-signed.badssl.com的服务器,这可能会使您的机密信息面临风险。 ---&GT;   Foundation.NSErrorException:抛出了类型'Foundation.NSErrorException'的异常。

此错误是由于即使允许ATS例外,iOS提供的默认 HttpClient也会将其标准NSUrlSession应用于证书,失败,因为自签名证书永远不能真正进行身份验证(即使是通过客户端固定),因为它的链中不包含iOS信任的根证书颁发机构(CA)。

因此,您需要拦截并绕过iOS提供的证书安全检查(是的,大安全警报,闪烁的红灯等......)

但是,您可以通过创建执行旁路的NSUrlAuthenticationChallenge子类来完成此操作。

NSUrlSessionDataDelegate

现在您需要将public class SelfSignedSessionDataDelegate : NSUrlSessionDataDelegate, INSUrlSessionDelegate { const string host = "self-signed.badssl.com"; public override void DidReceiveChallenge(NSUrlSession session, NSUrlAuthenticationChallenge challenge, Action<NSUrlSessionAuthChallengeDisposition, NSUrlCredential> completionHandler) { switch (challenge.ProtectionSpace.Host) { case host: using (var cred = NSUrlCredential.FromTrust(challenge.ProtectionSpace.ServerSecTrust)) { completionHandler.Invoke(NSUrlSessionAuthChallengeDisposition.UseCredential, cred); } break; default: completionHandler.Invoke(NSUrlSessionAuthChallengeDisposition.PerformDefaultHandling, null); break; } } } 应用于NSUrlSessionDataDelegate并在创建NSUrlSession时使用该新会话,该会话将在NSUrlSessionHandler的构造函数中提供

HttpClient

注意:仅限示例,通常您将创建一个Delegate,NSUrlSession,HttpClient,NSUrlSessionHandler并将其重新用于您的所有请求(即Singleton模式)

您的请求现在有效:

var url = "https://self-signed.badssl.com";
using (var selfSignedDelegate = new SelfSignedSessionDataDelegate())
using (var session = NSUrlSession.FromConfiguration(NSUrlSession.SharedSession.Configuration, (INSUrlSessionDelegate)selfSignedDelegate, NSOperationQueue.MainQueue))
using (var handler = new NSUrlSessionHandler(session))
using (var httpClient = new HttpClient(handler))
using (var response = await httpClient.GetAsync(url))
using (var content = response.Content)
{
    var result = await content.ReadAsStringAsync();
    Console.WriteLine(result);
}

注意:向Xamarin <html> <head> <title>self-signed.badssl.com</title> </head> <body><div id="content"><h1 style="font-size: 12vw;"> self-signed.<br>badssl.com </h1></div> </body> </html> 提供自定义NSUrlSession的选项实际上是(2017年11月),目前尚未发布版本(alpha,beta或stable),但当然,源代码位于:

使用NSUrlSessionHandler代替NSUrlSession

您还可以直接对自签名证书使用HttpClient代替NSUrlSession

HttpClient

注意:仅限示例,通常您会创建一个Delegate和NSUrlSession并将其重新用于您的所有请求,即Singleton模式

真正的解决方案?使用免费安全证书:

IHMO,即使在开发环境中也要避免使用自签名证书,并使用其中一种免费证书服务,避免应用ATS异常,拦截/绕过iOS安全等的自定义代码等等......使您的应用Web服务真正安全。

我个人使用Let's Encrypt: