Enabling specific SSL protocols with Android WebViewClient
Solution 1
As per documenation it is NOT possible to support TLS 1.0 in WebView in Android < 4.3. For Android 4.4 it is disabled by default.
Check this chart for support of TLS 1.0 in different browsers: https://en.wikipedia.org/wiki/Transport_Layer_Security#Web_browsers
Solution 2
If your app is using, or you are willing to use, Google Play services, you can use newer security features on older phones by installing their Provider
. It is easy to install, only one line (plus exception handling, etc). You will also need to add google play services to your gradle file if you do not already have it. ProviderInstaller
is included in the -base
package.
try {
ProviderInstaller.installIfNeeded(this);
} catch (GooglePlayServicesRepairableException e) {
// Fix it
} catch (GooglePlayServicesNotAvailableException e) {
// Skip it
}
For a full example, see "Updating Your Security Provider to Protect Against SSL Exploits" from Google.
Solution 3
Actually, I managed to make it work, but you need okHttp library for that. Try this when you're setting up browser activity:
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);
Also, you'll need classic Trust Manager Manipulator, SSL socket factory and its implementation in your Application class:
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;
}
}
App class:
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();
}
}
}
Related videos on Youtube
user802467
Updated on July 09, 2022Comments
-
user802467 almost 2 years
My application uses
WebViewClient
to make SSL connections to the server. The server is configured to only accept TLSv1.1 and above protocols.- How do I check which SSL protocols are a) Supported and b) Enabled by default when using Android
WebViewClient
on a device. - How do I enable specific SSL protocols for Android WebViewClient instance used in my application.
On one of the test devices running Android 4.3,
WebViewClient
throwsonReceivedError
callback with the following description:"Failed to perform SSL handshake"
Chrome logs are as follows:
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)] Falling back to SSLv3 because host is TLS intolerant: 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)] handshake failed; returned 0, SSL error code 5, net_error -107
My application also uses
HttpClient
andHttpsUrlConnection
classes to setup SSL Connections. I was able to useSSLSocket
API to enable specific protocols when using these classes. http://developer.android.com/reference/javax/net/ssl/SSLSocket.html#setEnabledProtocols(java.lang.String[])I need to do the same with
WebViewClient
.-
Robert over 9 yearsAFAIK the enabled protocols WebView can not be cahnged by an App. What protocols are supported or not depends on the Android version. For TLS 1.1 and higher you need an Android 4.4 or newer (see here).
-
cynod almost 9 yearsDid anyone ever figure this out? I'm working on a project currently where we need to fallback from TLS v1.2 to 1.1 for three non-production test servers. We're trying to use something like this: adb shell 'echo "browser --show-fps-counter --ssl-version-min=tls1.1 --ssl-version-max=tls1.1" > /data/local/tmp/webview-command-line' The FPS counter shows on an Android L tablet but not on Android TV (which is weird as they should be the same webview code). The ssl-version flags don't seem to work; a tcpdump capture from the device still shows TLS v1.2 being used. Any help would be great.
-
KK_07k11A0585 almost 9 years@user802467 Did you find solution for the issue ?? I am also facing the same issue
-
user802467 almost 9 years@KK_07k11A0585 No, I couldn't find a way to configure this in WebViewClient. I think comment above from Robert is correct.
-
Ultimo_m almost 6 years
- How do I check which SSL protocols are a) Supported and b) Enabled by default when using Android
-
Lucas Crawford over 8 yearsNote: This is the synchronous call that is called on the main thread (the UI thread). You can run this call in a SyncAdapter that operates in the background or an AsyncTask to perform this attempt to update, or call using the installIfNeededAsync version of this call to avoid blocking the main thread
-
ua741 over 8 yearsAlso, even after installing the provider successfully, you need to enable TLS 1.2/TLS 1.1 explicitly while making https request in Android Versions between [16-20]. I verified this on a KITKAT device.
-
Pavel Biryukov about 8 yearsDo you mean "...to support TLS 1.1" (instead of 1.0) ?
-
frank almost 8 yearsNote: This doesn't seem to resolve the issue with 4.1.2 clients.
-
ar-g almost 8 yearsUnfortunately, I only see plain text in my webView; it probably depends on the execution of javaScript. Also found this post artemzin.com/blog/android-webview-io
-
Alexander Zar over 7 years@ar-g Have you solved your problem?Please let me know if you done it.
-
ar-g over 7 years@AlexanderZarovniy the problem was in 3rd-party service, we use different scheme for android below 4.4(it's not related to android)
-
Agent_L over 7 years@frank lowest version I managed to get it working was 4.4.2. Intercepting socket creation and calling
setEnabledProtocols
seems to be the only solution there. -
frank almost 7 yearsDoes this still work for anyone? I've noticed my 4.4 devices no longer load TLS 1.2 served content.
-
Nick almost 6 yearsWelcome to SO. Your answer appears to suggest much the same as the first comment on the OP. See stackoverflow.com/help/how-to-answer for guidance.
-
Johnny Five about 5 yearsIt says
Disabled by default
from 4.1 to 4.4. So how to enable it?