Подтвердить что ты не робот

Включение определенных SSL-протоколов с помощью Android WebViewClient

Мое приложение использует WebViewClient для подключения SSL к серверу. Сервер настроен только для приема протоколов TLSv1.1 и выше.

1) Как проверить, какие SSL-протоколы являются a) Поддерживается и b) Включено по умолчанию при использовании Android WebViewClient на устройстве.
2) Как включить определенные SSL-протоколы для экземпляра Android WebViewClient, который используется в моем приложении.

На одном из тестовых устройств под управлением Android 4.3, WebViewClient запускает обратный вызов onReceivedError с описанием "Не удалось выполнить SSL-квитирование"
Журналы Chrome следующие:
01-29 15: 58: 00.073 5486 5525 W chromium_net: external/chromium/net/http/http_stream_factory_impl_job.cc: 865: [0129/155800: ПРЕДУПРЕЖДЕНИЕ: http_stream_factory_impl_job.cc(865)] Возврат к SSLv3, поскольку хост является нетерпимым TLS: 10.209.126.125:443 01-29 15: 58: 00.083 5486 5525 E chromium_net: external/chromium/net/socket/ssl_client_socket_openssl.cc: 792: [0129/155800: ERROR: ssl_client_socket_openssl.cc(792)] не выполнено; 0, код ошибки SSL 5, net_error -107

Мое приложение также использует классы HttpClient и HttpsUrlConnection для настройки SSL-соединений. Я смог использовать SSLSocket API для включения определенных протоколов при использовании этих классов. http://developer.android.com/reference/javax/net/ssl/SSLSocket.html#setEnabledProtocols(java.lang.String[])

Мне нужно сделать то же самое с WebViewClient.

4b9b3361

Ответ 1

В соответствии с документацией невозможно поддерживать TLS 1.0 в WebView в Android < 4,3. Для Android 4.4 он по умолчанию отключен.

Проверьте эту таблицу для поддержки TLS 1.0 в разных браузерах: https://en.wikipedia.org/wiki/Transport_Layer_Security#Web_browsers

Ответ 2

Если ваше приложение использует или вы хотите использовать службы Google Play, вы можете использовать более новые функции безопасности на старых телефонах, установив их Provider. Он прост в установке, только одна строка (плюс обработка исключений и т.д.). Вам также нужно будет добавить сервисы google play к вашему файлу gradle, если у вас его еще нет. ProviderInstaller включен в пакет -base.

try {
    ProviderInstaller.installIfNeeded(this);
} catch (GooglePlayServicesRepairableException e) {
     // Fix it
} catch (GooglePlayServicesNotAvailableException e) {
     // Skip it
}

Полный пример см. в "Обновление вашего поставщика безопасности для защиты от SSL-эксплойтов" от Google.

Ответ 3

На самом деле мне удалось заставить его работать, но для этого вам нужна библиотека okHttp. Попробуйте это, когда вы настраиваете активность браузера:

    WebViewClient client = new WebViewClient() {
        private OkHttpClient okHttp = new OkHttpClient.Builder().build();

        @Override
        public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
            Request okHttpRequest = new Request.Builder().url(url).build();
            try {
                Response response = okHttp.newCall(okHttpRequest).execute();
                return new WebResourceResponse(response.header("Content-Type", "plain/text"), response.header("Content-Encoding", "deflate"), response.body().byteStream());
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
    };
    webView.setWebViewClient(client);

Кроме того, вам понадобится классический Манипулятор Trust Manager, SSL-сокет factory и его реализация в вашем классе Application:

public class TrustManagerManipulator implements X509TrustManager {


    private static TrustManager[] trustManagers;
    private static final X509Certificate[] acceptedIssuers = new X509Certificate[] {};

    public boolean isClientTrusted(X509Certificate[] chain) {
        return true;
    }

    public boolean isServerTrusted(X509Certificate[] chain) {
        return true;
    }

    public static void allowAllSSL()
    {

        HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        });
        SSLContext context = null;
        if (trustManagers == null) {
            trustManagers = new TrustManager[] { new TrustManagerManipulator() };
        }
        try {
            context = SSLContext.getInstance("TLS");
            context.init(null, trustManagers, new SecureRandom());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }
        HttpsURLConnection.setDefaultSSLSocketFactory(context
                .getSocketFactory());
    }

    public void checkClientTrusted(X509Certificate[] chain, String authType)
            throws CertificateException {
    }

    public void checkServerTrusted(X509Certificate[] chain, String authType)
            throws CertificateException {
    }

    public X509Certificate[] getAcceptedIssuers() {
        return acceptedIssuers;
    }
}

SSl Socket Factory:

public class TLSSocketFactory extends SSLSocketFactory {

    private SSLSocketFactory internalSSLSocketFactory;

    public TLSSocketFactory() throws KeyManagementException, NoSuchAlgorithmException {
        SSLContext context = SSLContext.getInstance("TLS");
        TrustManager[] managers = new TrustManager[] { new TrustManagerManipulator() };
        context.init(null, managers, new SecureRandom());
        internalSSLSocketFactory = context.getSocketFactory();
    }

    @Override
    public String[] getDefaultCipherSuites() {
        return internalSSLSocketFactory.getDefaultCipherSuites();
    }

    @Override
    public String[] getSupportedCipherSuites() {
        return internalSSLSocketFactory.getSupportedCipherSuites();
    }

    @Override
    public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
        return enableTLSOnSocket(internalSSLSocketFactory.createSocket(s, host, port, autoClose));
    }

    @Override
    public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
        return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
    }

    @Override
    public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
        return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port, localHost, localPort));
    }

    @Override
    public Socket createSocket(InetAddress host, int port) throws IOException {
        return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
    }

    @Override
    public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
        return enableTLSOnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort));
    }

    private Socket enableTLSOnSocket(Socket socket) {
        if(socket != null && (socket instanceof SSLSocket)) {
            ((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1.2"});
        }
        return socket;
    }
}

Класс приложения:

public class App extends Application {
    private static App appInstance;

    @Override
    public void onCreate() {
        super.onCreate();

        setupSSLconnections();
    }

    private void setupSSLconnections() {
        try {
            HttpsURLConnection.setDefaultSSLSocketFactory(new TLSSocketFactory());
        } catch (KeyManagementException | NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }
}