2015-02-04 20 views
22

La mia applicazione utilizza WebViewClient per effettuare connessioni SSL al server. Il server è configurato per accettare solo TLSv1.1 e protocolli precedenti.Abilitazione di protocolli SSL specifici con Android WebView Client

1) Come controllare quali protocolli SSL sono a) Supportati e b) Abilitati per impostazione predefinita quando si utilizza Android WebViewClient su un dispositivo.
2) Come abilitare protocolli SSL specifici per l'istanza di WebViewClient Android utilizzata nella mia applicazione.

Su uno dei dispositivi di test con sistema operativo Android 4.3, WebViewClient tiri callback onReceivedError con la descrizione "Impossibile eseguire l'handshake SSL"
tronchi Chrome sono i seguenti:
01-29 15: 58: 00.073 5486 5525 W chromium_net : external/chromium/net/http/http_stream_factory_impl_job.cc: 865: [0129/155800: WARNING: http_stream_factory_impl_job.cc (865)] Ritorno a SSLv3 perché l'host è intollerante 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: ERRORE: ssl_client_socket_openssl.cc (792)] handshake non riuscito; restituito 0, codice errore SSL 5, net_error -107

La mia applicazione utilizza anche le classi HttpClient e HttpsUrlConnection per configurare Connessioni SSL. Sono stato in grado di utilizzare l'API SSLSocket per abilitare protocolli specifici quando si utilizzano queste classi. http://developer.android.com/reference/javax/net/ssl/SSLSocket.html#setEnabledProtocols(java.lang.String[])

Ho bisogno di fare lo stesso con WebViewClient.

+1

AFAIK i protocolli abilitati WebView non possono essere coperti da un'app. Quali protocolli sono supportati o meno dipende dalla versione di Android. Per TLS 1.1 e versioni successive è necessario un Android 4.4 o successivo (consultare [qui] (https://www.ssllabs.com/ssltest/viewClient.html?name = Android & version = 4.3)). – Robert

+0

Qualcuno lo ha mai capito? Sto lavorando a un progetto al momento in cui dobbiamo eseguire il fallback da TLS v1.2 a 1.1 per tre server di prova non di produzione. Stiamo cercando di utilizzare qualcosa di simile: browser adb "echo" --show-fps-counter --ssl-version-min = tls1.1 --ssl-version-max = tls1.1 ">/data/local/tmp/webview-command-line ' Il contatore FPS viene visualizzato su un tablet Android L ma non su Android TV (il che è strano dato che dovrebbero essere lo stesso codice webview). I flag della versione ssl non sembrano funzionare; una cattura tcpdump dal dispositivo mostra ancora TLS v1.2 in uso. Qualsiasi aiuto sarebbe fantastico. – cynod

+0

@ user802467 Hai trovato la soluzione per il problema ?? Sto anche affrontando lo stesso numero –

risposta

3

Se la tua app utilizza o sei disposto a utilizzare i servizi di Google Play, puoi utilizzare le nuove funzionalità di sicurezza sui telefoni più vecchi installando il loro Provider. È facile da installare, solo una riga (oltre alla gestione delle eccezioni, ecc.). Dovrai anche aggiungere i servizi di google play al tuo file gradle se non lo hai già. ProviderInstaller è incluso nel pacchetto -base.

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

Per un esempio completo, vedere "Updating Your Security Provider to Protect Against SSL Exploits" da Google.

+1

Nota: questa è la chiamata sincrona chiamata sul thread principale (il thread dell'interfaccia utente). È possibile eseguire questa chiamata in un SyncAdapter che opera in background o in un AsyncTask per eseguire questo tentativo di aggiornamento o chiamare utilizzando la versione installIfNeededAsync di questa chiamata per evitare di bloccare il thread principale –

+2

Inoltre, anche dopo aver installato correttamente il provider, è necessario per abilitare TLS 1.2/TLS 1.1 esplicitamente mentre si effettua la richiesta https nelle versioni Android tra [16-20]. Ho verificato questo su un dispositivo KITKAT. – ua741

+1

Nota: questo non sembra risolvere il problema con i client 4.1.2. – frank

7

Come da documentazione NON è possibile supportare TLS 1.0 in WebView in Android < 4.3. Per Android 4.4 è disabilitato per impostazione predefinita.

Controllare questo grafico per il supporto di TLS 1.0 in diversi browser: https://en.wikipedia.org/wiki/Transport_Layer_Security#Web_browsers

+7

Intendi "... per supportare TLS 1.1" (anziché 1.0)? –

2

In realtà, sono riuscito a farlo funzionare, ma è necessario biblioteca okHttp per questo. Prova questo quando si sta impostando l'attività del browser:

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

Inoltre, avrete bisogno di classico Gestore affidabilità manipolatore, fabbrica presa SSL e la sua attuazione nella classe di applicazione:

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 fabbrica:

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 classe:

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

Purtroppo, vedo solo testo nella mia webView; probabilmente dipende dall'esecuzione di javaScript. Ho trovato anche questo post https://artemzin.com/blog/android-webview-io/ –

+0

@ ar-g Hai risolto il problema? Per favore fatemi sapere se l'avete fatto. –

+0

@AlexanderZarovniy il problema era nel servizio di terze parti, usiamo schema diverso per Android inferiore a 4.4 (non è correlato ad Android) –