使用Httpclient信任自签名证书 [英] Trust a self signed certificate using Httpclient

查看:131
本文介绍了使用Httpclient信任自签名证书的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试由于自签名证书而失败的Web请求:

I'm attempting to make a web request that's failing because of a self signed certificate :

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

信任失败异常。

我再次使用 httpclienthandler 尝试过,如此处建议的那样允许HttpClient使用不受信任的SSL证书

I tried again using httpclienthandler as suggested here Allowing Untrusted SSL Certificates with HttpClient:

 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); 

这会抛出系统未实现的异常。

This blows up throwing a system not implemented exception.

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

Are there any other ways to trust a self signed cert? I've even installed the certificate on the machine making the request but no luck.

推荐答案

我对此有很多疑问我想我会尽可能写完整的答案和示例。

I have seen so many question regarding this I figured I write up as a complete answer and example as I can.

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

Note: Using WKWebView with self-sign certs, see this answer

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


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

System.Net.Http.HttpRequestException: An error occurred while sending the request ---> System.Net.WebException: Error: TrustFailure (One or more errors occurred.) ---> System.AggregateException: One or more errors occurred. ---> System.Security.Authentication.AuthenticationException: A call to SSPI failed, see inner exception. ---> Mono.Security.Interface.Tl

原始Mono 托管提供程序的使用期限越来越长,并且在安全性和安全性方面仅支持TLS1.0。性能我将转向使用NSUrlSession实现。

The original Mono Managed provider is getting really long in the tooth and only supports TLS1.0, in terms of security & performance I would move to using the NSUrlSession implementation.

注意: iOS版本现在已经相当老了,我个人不再针对它,所以我将其留空……(除非有人真的需要我为它查找笔记;-)

Note: As this iOS version is fairly old now and I personally do not target it anymore, so I leave this blank... (unless someone really needs me to lookup my notes for it ;-)

Xamarin提供了 HttpMessageHandler 子类( NSUrlSessionHandler )基于iOS的 NSUrlSession

Xamarin provides a HttpMessageHandler subclass (NSUrlSessionHandler) that is based upon iOS' NSUrlSession.

将其自身用于自签名证书将导致:

Using it by itself against a self-signed cert will result in:


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

System.Net.WebException: An SSL error has occurred and a secure connection to the server cannot be made. ---> Foundation.NSErrorException: Exception of type 'Foundation.NSErrorException' was thrown.

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

The problem is that a self-sign cert is considered insecure and non-trusted by iOS, thus you have to apply an ATS exception to your app so iOS knows that your app is untrusted in the Info.plist.

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSExceptionDomains</key>
    <dict>
        <key>self-signed.badssl.com</key>
        <dict>
            <key>NSExceptionAllowsInsecureHTTPLoads</key>
            <true/>
        </dict>
    </dict>
</dict>

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

Now that iOS knows that your app is making untrusted calls, a HttpClient request will now result in this error:


System.Net.WebException:该服务器的证书无效。您可能正在连接到假装为self-signed.badssl.com的服务器,这可能会使您的机密信息受到威胁。 --->
Foundation.NSErrorException:引发了类型为'Foundation.NSErrorException'的异常。

System.Net.WebException: The certificate for this server is invalid. You might be connecting to a server that is pretending to be‚ self-signed.badssl.com‚ which could put your confidential information at risk. ---> Foundation.NSErrorException: Exception of type 'Foundation.NSErrorException' was thrown.

此错误是由于即使允许ATS例外,iOS提供的默认 NSUrlSession 仍将应用其标准的 NSUrlAuthenticationChallenge 证书失败,因为自签名证书永远无法得到真正的身份验证(甚至无法通过客户端固定),因为它的链中没有受iOS信任的根证书颁发机构(CA)。

This error is due to the fact that even though the ATS exception has been allow, the default NSUrlSession provided by iOS will apply its standard NSUrlAuthenticationChallenge to the certificate and fail since a self-signed cert can never be truly authenticated (even via client pinning) since it does not include a root certificate authority (CA) in its chain that is trusted by iOS.

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

Thus you need to intercept and bypass the certificate security checking provided by iOS (Yes, a big security alert, flashing red lights, etc...)

但是,您可以通过创建一个进行旁路的 NSUrlSessionDataDelegate 子类来实现。

But, you can do this via creating a NSUrlSessionDataDelegate subclass that does the bypass.

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 的构造函数中提供。

Now you need to apply that NSUrlSessionDataDelegate to a NSUrlSession and use that new session in the creation of your NSUrlSessionHandler that will be provided in the constructor of the 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);
}

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

Note: Example only, normally you would create a single Delegate, NSUrlSession, HttpClient, NSUrlSessionHandler and re-use it for all your requests (i.e. Singleton pattern)

您的请求现在可以使用了:

Your request now works:

<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>

注意:提供您自己的自定义 Xamarin的 NSUrlSessionHandler 的> NSUrlSession 确实是(2017年11月),目前不在发行版中(alpha, beta或稳定版),但当然可以在以下位置找到源:

Note: The option to supply your own custom NSUrlSession to Xamarin's NSUrlSessionHandler is really new (Nov. 2017) and not currently in a release build (alpha, beta or stable), but of course, source is available at:

  • xamarin-macios/src/Foundation/NSUrlSessionHandler.cs

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

You can also directly use a NSUrlSession instead of HttpClient against a self-signed cert.

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模式

Note: Example only, normally you would create a single Delegate and NSUrlSession and re-use it for all your requests, i.e. Singleton pattern

IHMO,即使在开发环境中也要避免一起使用自签名证书,并使用其中一种免费证书服务,并避免所有麻烦的申请ATS异常,拦截/绕过iOS安全性的自定义代码等,并使您的应用程序网络服务真正安全。

IHMO, avoid self-signed certs all together, even in a development environment and use one of the free certificate services and avoid all the headaches of applying ATS exceptions, custom code to intercept/bypass iOS security, etc... and make your app web services actually secure.

我个人使用让我们加密:

I personally use Let’s Encrypt:

  • https://letsencrypt.org

这篇关于使用Httpclient信任自签名证书的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆