Как заставить Trust якоря работать должным образом на уровнях Android API 16-19 - PullRequest
0 голосов
/ 03 октября 2018

Я работаю над проектом, который должен поддерживать уровень API до 16 и требует от меня сетевых вызовов динамических URL-адресов.Проблема, с которой я столкнулся, заключается в том, что серверу недавно пришлось обновить TLS до 1.2 для соответствия PCI, который по умолчанию отключен в Android API 16-19.Хотя включить это не сложно, я сталкиваюсь с проблемой сертификатов X509 только для этих уровней API.

Я провел немало исследований, и хотя все эти ссылки были полезны:

1) Как включить поддержку TLS 1.2 в приложении Android (работающем на Android 4.1JB)

2) Как использовать самозаверяющий сертификат для подключения к серверу Mqtt в Android (клиент Paho)?

3) SSLSocketFactory в java

4) Разрешение Java использовать ненадежный сертификат для соединения SSL / HTTPS

5) Не найдена привязка доверия для Android SSLСоединение

6) SSLHandshakeException: доверенная привязка для пути сертификации не найдена.Только для Android API <19 </a>

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 для работы с веб-сайтами, такими как Этот на уровнях API 16-19, как они делают на уровнях API 20 +?

Спасибо за ваше время.

1 Ответ

0 голосов
/ 15 октября 2018

Вы можете использовать этот метод для этой ошибки

Эта ошибка получается из "https://", мы использовали" s "в нашем базовом URL

и изменили время 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);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...