2015-02-04 2 views
22

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

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.

+1

AFAIK разрешенные протоколы WebView не может быть привязан к приложению. Какие протоколы поддерживаются или нет, зависит от версии Android. Для TLS 1.1 и выше вам нужен Android 4.4 или новее (см. [Здесь] (https://www.ssllabs.com/ssltest/viewClient.html?имя = Android-версия = 4,3)). – Robert

+0

Кто-нибудь когда-нибудь это понял? Я сейчас работаю над проектом, где нам нужно отступить от TLS v1.2 до 1.1 для трех непроизводительных тестовых серверов. Мы пытаемся использовать что-то вроде этого: браузер adb shell 'echo' --show-fps-counter --ssl-version-min = tls1.1 --ssl-version-max = tls1.1 ">/data/local/tmp/webview-command-line ' Счетчик FPS отображается на планшете Android L, но не на Android TV (что странно, поскольку они должны быть одним и тем же кодом веб-просмотра). Флаги ssl-версии, похоже, не работают; tcpdump захват с устройства все еще показывает TLS v1.2. Любая помощь будет замечательной. – cynod

+0

@ user802467 Вы нашли решение проблемы? Я также сталкиваюсь с тем же вопросом –

ответ

3

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

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

Полный пример см. В "Updating Your Security Provider to Protect Against SSL Exploits" от Google.

+1

Примечание. Это синхронный вызов, который вызывается в основном потоке (поток пользовательского интерфейса). Вы можете запустить этот вызов в SyncAdapter, который работает в фоновом режиме или в AsyncTask, чтобы выполнить эту попытку для обновления, или вызвать с помощью версии этого вызова, чтобы избежать блокировки основного потока. –

+2

Кроме того, даже после установки провайдера вам необходимо чтобы включить TLS 1.2/TLS 1.1 явно, делая https-запрос в версиях Android между [16-20]. Я проверил это на устройстве KITKAT. – ua741

+1

Примечание. Это не похоже на проблему с клиентами 4.1.2. – frank

7

В соответствии с документооборотом НЕ возможно поддерживать TLS 1.0 в WebView на Android. < 4.3. Для Android 4.4 он по умолчанию отключен.

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

+7

Вы имеете в виду «... для поддержки TLS 1.1» (вместо 1.0)? –

2

На самом деле, мне удалось заставить его работать, но вам нужно 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 завод и его реализация в классе 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 Гнездо Фабрика:

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; 
    } 
} 

App класс:

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(); 
     } 
    } 
} 
+1

К сожалению, я вижу только простой текст в своем веб-браузере; это, вероятно, зависит от выполнения javaScript. Также нашел это сообщение https://artemzin.com/blog/android-webview-io/ –

+0

@ ar-g Вы решили свою проблему? Пожалуйста, дайте мне знать, если вы это сделали. –

+0

@ Александр Заровный проблема была в стороннем сервисе, мы используем разную схему для Android ниже 4.4 (это не связано с Android) –

Смежные вопросы