1

我的 Xamarin.Android 应用程序向在 https 上运行的 Web 服务发出请求。证书可能是自签名的,所以我需要自己进行证书检查。我配置了自己的 TrustManager。但是根据我的发现,如果证书不受信任,该方法CheckServerTrusted应该抛出一个。CertificateException如果我这样做,那么我的应用程序就会崩溃。CertificateException不在任何地方处理。

var aUrl = new URL(url);
var connection = (HttpURLConnection)aUrl.OpenConnection();

try
{
    var httpsConn = connection as HttpsURLConnection;
    if (httpsConn != null)
    {
        var tm = new CustomX509TrustManager();
        var sslCtx = SSLContext.GetInstance("TLSv1.2");
        sslCtx.Init(null, new ITrustManager[] { tm }, null);

        httpsConn.HostnameVerifier = new CustomHostnameVerifier();
        httpsConn.SSLSocketFactory = sslCtx.SocketFactory;
    }

    System.Diagnostics.Debug.WriteLine("Connecting ...");

    //connection.Connect();
    await connection.ConnectAsync();

    System.Diagnostics.Debug.WriteLine("Never reached");
}
catch (Exception ex)
{
    System.Diagnostics.Debug.WriteLine($"Exception!\n{ex}");
}
finally
{
    System.Diagnostics.Debug.WriteLine("Never reached");
}
System.Diagnostics.Debug.WriteLine("Never reached");

CustomX509TrustManager尽可能简单:

class CustomX509TrustManager : Java.Lang.Object, IX509TrustManager
{
    public void CheckClientTrusted(Java.Security.Cert.X509Certificate[] chain, string authType)
    {
    }

    public void CheckServerTrusted(Java.Security.Cert.X509Certificate[] certificates, string authType)
    {
        throw new Java.Security.Cert.CertificateException();
    }

    Java.Security.Cert.X509Certificate[] IX509TrustManager.GetAcceptedIssuers()
    {
        return new Java.Security.Cert.X509Certificate[0];
    }
}

在 connection.ConnectAsync() 中,远程服务器被联系并在 CustomX509TrustManager.CheckServerTrusted 中检查证书。这将引发 CertificateException。但是我在调​​用方法中的 try/catch 中没有捕获到该异常。应用程序因此堆栈跟踪而崩溃:

UNHANDLED EXCEPTION:
Java.Security.Cert.CertificateException: Exception of type 'Java.Security.Cert.CertificateException' was thrown.
  at SimpleWebRequest.MainActivity+CustomX509TrustManager.CheckServerTrusted (Java.Security.Cert.X509Certificate[] certificates, System.String authType) [0x00001] in D:\Temp\SimpleWebRequest\SimpleWebRequest\MainActivity.cs:162 
  at Javax.Net.Ssl.IX509TrustManagerInvoker.n_CheckServerTrusted_arrayLjava_security_cert_X509Certificate_Ljava_lang_String_ (System.IntPtr jnienv, System.IntPtr native__this, System.IntPtr native_chain, System.IntPtr native_authType) [0x00028] in /Users/builder/data/lanes/4009/9578cdcd/source/monodroid/src/Mono.Android/platforms/android-25/src/generated/Javax.Net.Ssl.IX509TrustManager.cs:129 
  at (wrapper dynamic-method) System.Object:5109f213-8693-4899-a3db-70ed54baf307 (intptr,intptr,intptr,intptr)
  --- End of managed Java.Security.Cert.CertificateException stack trace ---

我尝试了几件事,结果很奇怪。

如果我使用connection.Connect()而不是ConnectAsync,则catch运行该块,但该finally块不运行,之后的代码也不再运行。使用ConnectAsync,该catch块也不会运行。

如果我得到默认的 TrustManager 并SSLSocketFactory像我一样设置它,那么它就可以工作。证书被拒绝并且可以捕获异常。所以我不认为我只是抓住了错误的线索。

如果我使用自己的 TrustManager,但我将调用委托给CheckServerTrusted默认的 TrustManager,那么它会失败,就像我自己抛出异常一样。

所以我认为我在我的CustomX509TrustManager或我如何将它传递给SSLSocketFactory.

不幸的是,当您搜索自定义 TrustMangagers 时,大多数人只想忽略所有证书错误。这对我有用,如果我确实检查了证书并想要拒绝它,就会出现问题。

4

2 回答 2

0

我有同样的问题。经过几个小时的尝试和错误,我发现异常仅在调试模式下未处理。如果应用程序是在发布模式下构建的,则会捕获异常。

于 2019-11-20T10:35:33.883 回答
0

但是根据我的发现,如果证书不受信任,CheckServerTrusted 方法应该抛出 CertificateException 。如果我这样做,那么我的应用程序就会崩溃。CertificateException 不在任何地方处理。

我认为问题正是您如何处理该CheckServerTrusted方法,您的编码如下:

public void CheckServerTrusted(Java.Security.Cert.X509Certificate[] certificates, string authType)
{
    throw new Java.Security.Cert.CertificateException();
}

CertificateException当你的CheckServerTrusted方法被调用时,这总是抛出一个未处理的新的。

我想你可以查看这个博客:Self-Signed Certificates and Xamarin.Android。据我所知,该CheckServerTrusted方法可用于将信任管理器包装在另一个信任管理器中,以允许验证其他证书。当你自定义这个方法时,你不需要抛出这样的异常。

于 2017-03-16T05:53:54.847 回答