Mon application utilise WebViewClient pour établir des connexions SSL avec le serveur . Le serveur est configuré pour accepter uniquement les protocoles TLSv1.1 et supérieurs.
1) Comment vérifier quels protocoles SSL sont a) pris en charge et b) activés par défaut lors de l'utilisation d'Android WebViewClient sur un appareil.
2) Comment activer des protocoles SSL spécifiques pour l'instance Android WebViewClient utilisée dans mon application.
Sur un des appareils de test exécutant Android 4.3, WebViewClient émet un rappel onReceivedError avec la description "Échec de l'établissement de la liaison SSL".
Les journaux Chrome sont les suivants:
01-29 15: 58: 00.073 5486 5525 W chromium_net: external/chromium/net/http/http_stream_factory_impl_job.cc: 865: [0129/155800: AVERTISSEMENT: http_stream_factory_impl_job.cc (865)] Retourner à SSLv3 parce que l'hôte TLS est intolérant: 10.209.126.125:443 01-29 15: 58: 00.083 5486 5525 E chrome_net: externe/chrome/filet/socket/ssl_client_socket_openssl.cc: 792: [0129/155800: ERREUR: ssl_client_opensslcc la poignée de main a échoué; a renvoyé 0, code d'erreur SSL 5, net_error -107
Mon application utilise également les classes HttpClient et HttpsUrlConnection pour configurer les connexions SSL. J'ai pu utiliser l'API SSLSocket pour activer des protocoles spécifiques lors de l'utilisation de ces classes . http://developer.Android.com/reference/javax/net/ssl/SSLSocket.html#setEnabledProtocols(Java.lang.String [])
Je dois faire la même chose avec WebViewClient.
Selon la documentation, il n'est PAS possible de prendre en charge TLS 1.0 dans WebView sous Android <4.3. Pour Android 4.4, il est désactivé par défaut.
Consultez ce tableau pour la prise en charge de TLS 1.0 dans différents navigateurs: https://en.wikipedia.org/wiki/Transport_Layer_Security#Web_browsers
Si votre application utilise, ou souhaitez utiliser, les services Google Play, vous pouvez utiliser les nouvelles fonctionnalités de sécurité sur les téléphones plus anciens en installant leur Provider
. Il est facile à installer, une seule ligne (plus la gestion des exceptions, etc.). Vous devrez également ajouter des services Google Play à votre fichier Gradle si vous ne l'avez pas déjà. ProviderInstaller
est inclus dans le package -base
.
try {
ProviderInstaller.installIfNeeded(this);
} catch (GooglePlayServicesRepairableException e) {
// Fix it
} catch (GooglePlayServicesNotAvailableException e) {
// Skip it
}
Pour un exemple complet, voir "Mise à jour de votre fournisseur de sécurité pour se protéger contre les attaques SSL" de Google.
En fait, j'ai réussi à le faire fonctionner, mais vous avez besoin de la bibliothèque okHttp pour cela . Essayez ceci lorsque vous configurez l'activité du navigateur:
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);
De plus, vous aurez besoin du classique Trust Manager Manipulator, de la fabrique de sockets SSL et de son implémentation dans votre classe d'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;
}
}
Classe d'application:
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();
}
}
}
c’est Android qui ne prend pas en charge TSL 1.1 mais uniquement TSL1.0lire cet article https://www.ssllabs.com/ssltest/clients.html find
Protocoles TLS 1.3 Non TLS 1.2 Non TLS 1.1 Non TLS 1.0 Oui SSL 3 INSECURER Oui SSL 2 Non