我的 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 时,大多数人只想忽略所有证书错误。这对我有用,如果我确实检查了证书并想要拒绝它,就会出现问题。