我正在做一个项目,该项目必须支持回到API级别16,并且需要我对动态URL进行网络调用。我遇到的问题是服务器最近必须将TLS更新到1.2以符合PCI规范,默认情况下在Android API 16-19上禁用了该规范。虽然启用它并不困难,但我仅针对那些API级别遇到了X509证书问题。
我已经对此进行了大量研究,而所有这些链接都很有用:
1)How to enable TLS 1.2 support in an Android application (running on Android 4.1 JB)
2)How to use a self signed certificate to connect to a Mqtt server in Android (paho client)?
4)Allowing Java to use an untrusted certificate for SSL/HTTPS connection
5)Trust Anchor not found for Android SSL Connection
6)SSLHandshakeException: Trust anchor for certification path not found. Only on Android API < 19
7)Trusting all certificates using HttpClient over HTTPS
他们没有解决我遇到的核心问题,即我看到此异常:
com.android.volley.NoConnectionError: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
at com.android.volley.toolbox.BasicNetwork.performRequest(BasicNetwork.java:151)
at com.android.volley.NetworkDispatcher.run(NetworkDispatcher.java:112)
Caused by: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:409)
at com.android.okhttp.Connection.upgradeToTls(Connection.java:146)
at com.android.okhttp.Connection.connect(Connection.java:107)
at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:294)
at com.android.okhttp.internal.http.HttpEngine.sendSocketRequest(HttpEngine.java:255)
at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:206)
at com.android.okhttp.internal.http.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:345)
at com.android.okhttp.internal.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:296)
at com.android.okhttp.internal.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:503)
at com.android.okhttp.internal.http.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:136)
at com.android.volley.toolbox.HurlStack.performRequest(HurlStack.java:110)
at com.android.volley.toolbox.BasicNetwork.performRequest(BasicNetwork.java:96)
... 1 more
当我尝试连接到需要TLS1.2的URL时,例如https://www.ssllabs.com/ssltest/viewMyClient.html。
从本质上讲,这归结于TrustManager的问题。
有两种获取TrustManager对象的方法(第一种方法比第二种方法更安全,因为第二种方法信任所有证书,这使SSL成为了争论的焦点):
第一种方法:
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init((KeyStore) null);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
X509TrustManager trustManager = (X509TrustManager) trustManagers[0];
第二种方法:
X509TrustManager trustManager = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException {}
public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException {}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
然后将它们与以下代码一起使用:
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(null, new TrustManager[] { trustManager }, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
如果我在API级别20+上使用第一个TrustManager,则上面列出的url可以正常工作,并且页面将被加载。如果在API级别16-19上使用第一个,它将抛出上面列出的异常。
如果我在任何16级以上的API级别上使用第二个TrustManager,该调用将起作用,但是,这在我的应用程序中留下了安全漏洞,因为我现在信任所有证书,并且使自己不受各种攻击的影响。
此处需要注意的另一点是,虽然上面的示例错误来自Volley库,但在使用Retrofit并获得相同结果时仍然会发生。
因此,我的问题是,如何利用X509TrustManager在API级别16-19上与This One之类的网站协同工作,就像在API级别20+上一样?
感谢您的时间。
答案 0 :(得分:0)
您可以针对此错误使用此方法
此错误来自“ https://”,我们在基本网址中使用了“ s”
并将connectTimeout时间更改为您的
public static OkHttpClient getUnsafeOkHttpClient() {
try {
final TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[]{};
}
}
};
// Install the all-trusting trust manager
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
// Create an ssl socket factory with our all-trusting manager
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]);
builder.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
builder.connectTimeout(6000, TimeUnit.SECONDS)
.readTimeout(6000, TimeUnit.SECONDS)
.writeTimeout(6000, TimeUnit.SECONDS).connectionPool(new ConnectionPool(50, 50000, TimeUnit.SECONDS));
return builder.build();
} catch (Exception e) {
throw new RuntimeException(e);
}
}