16

我正在尝试找到一种正确的方法来处理 Android Webview 中的 SSL 证书错误。我的目标是提供一种加载带有 SSL 证书错误的页面的方法,但让用户在尝试加载带有证书错误的 URL 时警告他安全性后选择加载页面。

我在线程中找到的最接近的解决方案建议覆盖 WebViewClient 如下:

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

但是,这基本上会在未经用户同意的情况下禁用 WebView 中的 SSL。

以下是我找到该解决方案的线程供参考:

Android WebView SSL“安全警告”

Android 上的 Web 视图是否支持 SSL?

Android WebView 未加载 HTTPS URL

带有客户端证书的android webview

在 Android 中使用 WIFI 时,Web 视图在加载 URL 后显示空白/白页

无法在 Android webview 上加载特定网页

WebView 为某些链接显示空白视图

Android WebView 阻止从 https 重定向到 http

忽略 webview 中的 ssl 证书请求

我继续实施了一个稍微不同的版本,它会提示用户:

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

该实现询问用户两次是否要加载页面,如果他两次回答是,则忽略错误并加载页面,否则取消页面加载。

第一次加载带有证书错误的 URL 时,WebViewClient.onReceivedSslError会被调用,但是如果用户继续遇到证书错误并被SslErrorHandler.proceed()调用,则以下次数相同的 URL 将WebViewClient.onReceivedSslError永远不会被再次调用:仅终止应用程序会重置此行为。

我希望WebViewClient.onReceivedSslError在加载带有证书错误的 URL 时被系统地调用,而不仅仅是第一次。我尝试调用这些方法但没有成功:

/** 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();

有人知道如何在调用WebViewClient.onReceivedSslError同一个 URL 后SslErrorHandler.proceed()多次调用 WebView 吗?

4

3 回答 3

8

永远不要覆盖 onReceivedSslError 方法。Goole play 会拒绝你的上传 最聪明的方法是处理 SSL 错误使用webSettings.setDomStorageEnabled(true);

于 2017-11-15T11:02:33.037 回答
2

是的,您可以像这里一样使用 clearSslPreferences() :

webView.clearSslPreferences()

它会清除你对这个 WebView 对象的决定

于 2017-11-09T15:55:23.617 回答
0

我只会发布 Tssomas 在原始问题的评论中给出的答案,因为经过这么长时间,它是唯一可靠的解决方案,即使它是一个 hack。

引用 Tssomas:

如果用户继续,则他们继续进行的偏好仅保留在该会话中(如果他们关闭应用程序并再次启动,对话框将重新显示)。因此,为了确保用户每次都能看到对话框,我所做的就是将不安全的 url 添加到数组列表中并添加一个检查,以便每次 webview 完成加载时,都会检查数组列表中 webview 的当前 url。那么当然,如果数组列表包含当前 url,则显示对话框.. 它根本不是一个漂亮的解决方案,但它可以工作......

这就是代码的样子......

//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);
    }
});
于 2017-11-16T15:48:43.083 回答