17

I am trying to find a proper way to handle SSL certificate errors in the Android Webview. My goal is to provide a way to load pages with SSL certificate errors, but let the user choose to load the page after warning him about security any time he tries to load a URL with certificate errors.

The closest solutions I found in threads suggest overriding the WebViewClient as following:

webView.setWebViewClient(new WebViewClient() {
    @Override
    public void onReceivedSslError(final WebView view, final SslErrorHandler handler, final SslError error) {
        handler.proceed();
    }
});

However this basically disables SSL in the WebView without the user consent.

For reference here are the threads where I found that solution:

Android WebView SSL 'Security Warning'

Does the Web View on Android support SSL?

Android WebView not loading an HTTPS URL

android webview with client certificate

Web view shows blank/white page after loading URL when using WIFI in Android

Unable to load a specific webpage on Android webview

WebView displays a blank view for certain links

Android WebView blocks redirect from https to http

Ignore ssl certificate requests in webview

I went ahead and implemented a slightly different version which prompts the user:

webView.setWebViewClient(new WebViewClient() {
    @Override
    public void onReceivedSslError(final WebView view, final SslErrorHandler handler, final SslError error) {
        //Showing a first confirmation dialog
        AndroidUtils.showYesNoDialog(
            //First confirmation message
            "WARNING - THIS PAGE IS NOT SECURE! Are you sure you want to continue loading it?",
            //First confirmation "YES" option runnable
            new Runnable() {
                @Override
                public void run() {
                    //Showing a second confirmation dialog
                    AndroidUtils.showYesNoDialogWithResId(
                        //Second confirmation message
                        "You chose to load an unsecure page, are you sure you want to do that?",
                        //Second confirmation "YES" option runnable
                        new Runnable() {
                            @Override
                            public void run() {
                                //Disregard the error and proceed with the bad certificate anyways
                                handler.proceed();
                            }
                        },
                        //Second confirmation "NO" option runnable
                        new Runnable() {
                            @Override
                            public void run() {
                                //Cancel loading the page with that certificate error
                                handler.cancel();
                            }
                        }
                    );
                }
            },
            //First confirmation "NO" option runnable
            new Runnable() {
                @Override
                public void run() {
                    //Cancel loading the page with that certificate error
                    handler.cancel();
                }
            });
    }
});

This implementation asks the user twice if he wants to load the page, if he says yes twice, then the error is disregarded and the page loads, otherwise the page loading is canceled.

The first time a URL with certificate error loads, WebViewClient.onReceivedSslError is called, however if the user proceeds with the certificate error and SslErrorHandler.proceed() is called, the following times the same URL loads, WebViewClient.onReceivedSslError is never called again: only killing the app resets this behavior.

I would want WebViewClient.onReceivedSslError to be called systematically when a URL with a certificate error loads, not just the first time. I tried calling those methods without success:

/** JAVADOC QUOTE: Clears the SSL preferences table stored in response to proceeding with SSL certificate errors.*/
webView.clearSslPreferences();
//Those other methods I tried out of despair just in case
webView.clearFormData();
webView.clearCache(true);
webView.clearHistory();
webView.clearMatches();

Does anybody know how to make the WebView call WebViewClient.onReceivedSslError more than once for the same URL, after SslErrorHandler.proceed() has been called?

Community
  • 1
  • 1
androidseb
  • 1,257
  • 2
  • 14
  • 17
  • you got any solutions ?> – King of Masses Feb 29 '16 at 12:12
  • No I did not find any solution yet. – androidseb Feb 29 '16 at 16:16
  • @KingofMasses the night take so long in your country? just kidding, can you post please? i need this... – user2582318 Jun 11 '16 at 04:07
  • @KingofMasses, can you please post your solution? – Aleksandr Aug 30 '16 at 07:26
  • old question but still. – Tssomas Aug 25 '17 at 22:45
  • 2
    If the user proceeds, their preference to go ahead anyway is only kept for that session (if they close the app and start it again the dialog will re-show). So what i did to make sure the user sees the dialog every time was to add the unsecure url to an array list and add a check so that every time the webview finishes loading, the array list is checked for the webview's current url. So then of course, if the array list contains the current url, show the dialog.. its not a pretty solution at all but it works... – Tssomas Aug 25 '17 at 22:54
  • I would say that's the answer to my question! It's a hack but I don't see any other way... – androidseb Aug 28 '17 at 13:08

3 Answers3

8

Do not ever override onReceivedSslError method. Goole play will reject your upload. The smartest way is to handle SSL error, use webSettings.setDomStorageEnabled(true).

bluish
  • 26,356
  • 27
  • 122
  • 180
Chinthaka Devinda
  • 997
  • 5
  • 16
  • 36
  • Thanks very much bro, Google Play has rejected my update because of this issue but it's just accepted when setting the `setDomStorageEnabled` to `true` – Mahmoud Elshamy Nov 19 '17 at 02:18
  • 1
    @MahmoudElshamy you are welcome bro glad it worked :-) – Chinthaka Devinda Nov 19 '17 at 03:54
  • 1
    @ChinthakaDevinda could you explain how/why this works? How this has something to do with SSL error? Just curious about it. – WitaloBenicio Oct 09 '19 at 10:12
  • 1
    @WitaloBenicio I also do not have any idea about it but looks like it helps to ignore SSL error checks. By right webSettings.setDomStorageEnabled(true); only suppose to enable html5 storage capability. – Chinthaka Devinda Oct 17 '19 at 02:24
2

Yes, you can use clearSslPreferences() like here:

webView.clearSslPreferences()

It'll clear your decision for this object of WebView

Djek-Grif
  • 1,391
  • 18
  • 18
0

I will just post the answer that Tssomas has given in the original question's comments, because after all this time, it's the only solution that works reliably even though it's a hack.

Quoting Tssomas:

If the user proceeds, their preference to go ahead anyway is only kept for that session (if they close the app and start it again the dialog will re-show). So what i did to make sure the user sees the dialog every time was to add the unsecure url to an array list and add a check so that every time the webview finishes loading, the array list is checked for the webview's current url. So then of course, if the array list contains the current url, show the dialog.. its not a pretty solution at all but it works...

This is how the code might look like...

//This has to be static because it will be reset only once the app process is killed
private static final Set<String> unsecureURLSet = new TreeSet<>();

webView.setWebViewClient(new WebViewClient() {
    @Override
    public void onReceivedSslError(final WebView view, final SslErrorHandler handler, final SslError error) {
        //Adding the insecure URL to the set
        unsecureURLSet.add(error.getUrl());
        //Showing a first confirmation dialog
        AndroidUtils.showYesNoDialog(
            //First confirmation message
            "WARNING - THIS PAGE IS NOT SECURE! Are you sure you want to continue loading it?",
            //First confirmation "YES" option runnable
            new Runnable() {
                @Override
                public void run() {
                    //Showing a second confirmation dialog
                    AndroidUtils.showYesNoDialogWithResId(
                        //Second confirmation message
                        "You chose to load an unsecure page, are you sure you want to do that?",
                        //Second confirmation "YES" option runnable
                        new Runnable() {
                            @Override
                            public void run() {
                                //Disregard the error and proceed with the bad certificate anyways
                                handler.proceed();
                            }
                        },
                        //Second confirmation "NO" option runnable
                        new Runnable() {
                            @Override
                            public void run() {
                                //Cancel loading the page with that certificate error
                                handler.cancel();
                            }
                        }
                    );
                }
            },
            //First confirmation "NO" option runnable
            new Runnable() {
                @Override
                public void run() {
                    //Cancel loading the page with that certificate error
                    handler.cancel();
                }
            });
    }

    @Override
    public boolean shouldOverrideUrlLoading(final WebView _view, final String _url) {
        if (unsecureURLSet.contains(_url)){
            //Code here should mimic the dialog in onReceivedSslError
            //And replace the "handler.proceed()" with a forced load of _url
            return true;
        }
        return super.shouldOverrideUrlLoading(_view, _url);
    }
});
androidseb
  • 1,257
  • 2
  • 14
  • 17