Я работаю над проектом, который должен поддерживать уровень API 16 и требует, чтобы я выполнял сетевые вызовы для динамических URL-адресов. Проблема, с которой я сталкиваюсь, заключается в том, что серверу недавно пришлось обновить TLS до 1.2 для соответствия PCI, который по умолчанию отключен в Android API 16-19. Хотя включить это несложно, у меня возникла проблема с сертификатами X509 только для этих уровней API.
Я провел довольно много исследований по этому вопросу, и хотя все эти ссылки были полезны:
1) Как включить поддержку TLS 1.2 в приложении Android (работающем на Android 4.1 JB)
2) Как использовать самоподписанный сертификат для подключения к серверу Mqtt в Android (клиент paho)?
4) Разрешение Java использовать недоверенный сертификат для SSL/HTTPS-соединение
5) Якорь доверия не найден для SSL-соединения Android
6) SSLHandshakeException: якорь доверия для пути сертификации не нашел. Только для Android API ‹ 19
7) доверие всем сертификатам с использованием HttpClient через 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
Когда я пытаюсь подключиться к URL-адресу, для которого требуется TLS1.2, например https://www.ssllabs.com/ssltest/viewMyClient.html.
По сути, это сводится к проблеме с TrustManager.
Вот 2 разных способа получить объект 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());
Если я использую первый TrustManager на уровне API 20+, указанный выше URL-адрес будет работать нормально, и страница загрузится. Если я использую первый на уровнях API 16-19, он выдаст исключение, указанное выше.
Если я использую второй TrustManager на любом уровне API 16+, вызов будет работать, но он оставит брешь в безопасности моего приложения, потому что теперь я доверяю всем сертификатам и оставляю себя открытым для всех видов атак.
Еще одно замечание заключается в том, что, хотя приведенный выше пример ошибки относится к библиотеке Volley, он все еще возникает при использовании Retrofit с теми же результатами.
Поэтому мой вопрос заключается в том, как использовать X509TrustManager для работы с такими веб-сайтами, как This One на Уровни API 16-19 такие же, как на уровнях API 20+?
Спасибо за ваше время.