使用Httpclient信任自签名证书
我正在尝试通过自签名证书发出失败的Web请求:
Client = new HttpClient(); HttpResponseMessage Response = await Client.GetAsync(Uri)//defined elsewhere
这会引发信任失败exception。
我按照这里建议使用httpclienthandler
再次尝试使用HttpClient允许不受信任的SSL证书 :
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);
抛出一个未实现exception的系统。
有没有其他方法可以信任自签名证书? 我甚至在提出请求的机器上安装了证书,但没有运气。
我已经看到了很多这方面的问题,我想我尽可能地写完了答案和例子。
注意:将WKWebView
与自签名证书一起使用,请参阅此答案
HttpClient实现
注意:在此示例中使用badssl.com
管理(默认)
System.Net.Http.HttpRequestException:发送请求时发生错误—> System.Net.WebException:错误:TrustFailure(发生一个或多个错误。)—> System.AggregateException:发生一个或多个错误。 —> System.Security.Authentication.AuthenticationException:对SSPI的调用失败,请参阅内部exception。 —> Mono.Security.Interface.Tl
最初的Mono Managed
提供商正在变得非常长,只支持TLS1.0,在安全性和性能方面,我将转向使用NSUrlSession实现。
CFNetwork(iOS 6+)
注意:由于这个iOS版本现在相当老,我个人不再瞄准它了,所以我把它留空……(除非有人真的需要我为它查找我的笔记;-)
NSUrlSession(iOS 7+)
Xamarin提供了一个HttpMessageHandler
子类( NSUrlSessionHandler
)。
对自签名证书单独使用它将导致:
System.Net.WebException:发生SSL错误,无法建立与服务器的安全连接。 —> Foundation.NSErrorException:抛出了类型’Foundation.NSErrorException’的exception。
问题在于,自签名证书被iOS视为不安全且不受信任,因此您必须将ATS例外应用于您的应用,以便iOS知道您的应用在Info.plist
不受信任。
NSAppTransportSecurity NSExceptionDomains self-signed.badssl.com NSExceptionAllowsInsecureHTTPLoads
现在iOS知道您的应用程序正在进行不受信任的调用,现在HttpClient
请求将导致此错误:
System.Net.WebException:此服务器的证书无效。 您可能正在连接到假装为self-signed.badssl.com的服务器,这可能会使您的机密信息面临风险。 —> Foundation.NSErrorException:抛出了类型’Foundation.NSErrorException’的exception。
此错误是由于即使ATSexception已被允许,iOS提供的默认 NSUrlSession
也会将其标准NSUrlAuthenticationChallenge
应用于证书并失败,因为自签名证书永远无法真正进行身份validation(即使通过客户端固定)因为它的链中不包含受iOS信任的根证书颁发机构(CA)。
因此,您需要拦截并绕过iOS提供的证书安全检查(是的,一个大的安全警报,闪烁的红灯等……)
但是 ,您可以通过创建执行旁路的NSUrlSessionDataDelegate
子类来完成此操作。
public class SelfSignedSessionDataDelegate : NSUrlSessionDataDelegate, INSUrlSessionDelegate { const string host = "self-signed.badssl.com"; public override void DidReceiveChallenge(NSUrlSession session, NSUrlAuthenticationChallenge challenge, Action 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
并在创建将在HttpClient
的构造函数中提供的NSUrlSession
使用该新会话。
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); }
注意:仅示例,通常您将创建一个Delegate,NSUrlSession,HttpClient,NSUrlSessionHandler并将其重新用于您的所有请求(即Singleton模式)
您的请求现在有效:
self-signed.badssl.com self-signed.
badssl.com
注意:为Xamarin的NSUrlSessionHandler
提供自己的自定义NSUrlSession
的NSUrlSessionHandler
是新的 (2017年11月),目前还没有发布版本(alpha,beta或stable),但当然,源代码可在以下位置获得:
- xamarin-macios / src目录/基金/ NSUrlSessionHandler.cs
使用NSUrlSession
而不是HttpClient
:
您还可以直接对自签名证书使用NSUrlSession
而不是HttpClient
。
var url = "https://self-signed.badssl.com"; using (var selfSignedDelegate = new SelfSignedSessionDataDelegate()) using (var session = NSUrlSession.FromConfiguration(NSUrlSession.SharedSession.Configuration, (INSUrlSessionDelegate)selfSignedDelegate, NSOperationQueue.MainQueue)) { var request = await session.CreateDataTaskAsync(new NSUrl(url)); var cSharpString = NSString.FromData(request.Data, NSStringEncoding.UTF8).ToString(); Console.WriteLine(cSharpString); }
注意:仅示例,通常您将创建一个Delegate和NSUrlSession并将其重新用于所有请求,即Singleton模式
实解? 使用免费安全证书:
IHMO,即使在开发环境中也可以避免使用自签名证书,并使用免费证书服务之一,避免应用ATSexception,拦截/绕过iOS安全等的自定义代码……以及制作应用程序Web服务实际上是安全的
我个人使用Let的加密: