使用Httpclient信任自签名证书

Kis*_*agi 5 c# xamarin.ios dotnet-httpclient xamarin

我正在尝试通过自签名证书发出失败的Web请求:

Client = new HttpClient(); 
HttpResponseMessage Response = await Client.GetAsync(Uri)//defined elsewhere 
Run Code Online (Sandbox Code Playgroud)

这会引发信任失败异常.

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); 
Run Code Online (Sandbox Code Playgroud)

这会引发一个未实现异常的系统.

有没有其他方法可以信任自签名证书?我甚至在机器上安装了证书,但没有运气.

Sus*_*ver 8

我已经看到了很多这方面的问题,我认为我写的是一个完整的答案和例子.

注意:使用WKWebView自签名证书,请参阅此答案

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子类(NSUrlSessionHandler)NSUrlSession.

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

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

问题是iOS认为自签名证书不安全且不受信任,因此您必须将ATS例外应用于您的应用程序,以便iOS知道您的应用程序不受信任Info.plist.

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSExceptionDomains</key>
    <dict>
        <key>self-signed.badssl.com</key>
        <dict>
            <key>NSExceptionAllowsInsecureHTTPLoads</key>
            <true/>
        </dict>
    </dict>
</dict>
Run Code Online (Sandbox Code Playgroud)

现在iOS知道您的应用程序正在进行不受信任的调用,HttpClient现在请求将导致此错误:

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

此错误是由于即使ATS异常已被允许,iOS提供的默认值 NSUrlSession也会将其标准 NSUrlAuthenticationChallenge应用于证书并失败,因为自签名证书永远无法真正验证(即使通过客户端固定),因为它在其受信任的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<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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在你需要将它NSUrlSessionDataDelegate应用于a NSUrlSession并在创建你的NSUrlSessionHandler那个新的会话中使用它将在构造函数中提供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))
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);
}
Run Code Online (Sandbox Code Playgroud)

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

您的请求现在有效:

<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>
Run Code Online (Sandbox Code Playgroud)

注意:NSUrlSession为Xamarin 提供自定义的选项NSUrlSessionHandler新的(2017年11月),目前还没有发布版本(alpha,beta或stable),但当然,源代码可在以下位置获得:

使用NSUrlSession而不是HttpClient:

您也可以直接使用a 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);
}
Run Code Online (Sandbox Code Playgroud)

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

实解?使用免费安全证书:

IHMO,即使在开发环境中也避免使用自签名证书,并使用其中一种免费证书服务,避免应用ATS异常,拦截/绕过iOS安全等的自定义代码......以及制作应用程序Web服务实际上是安全的

我个人使用Let的加密: