Android Webview客户端证书,相互身份验证,Webview上的SSL

时间:2013-12-23 08:33:54

标签: android ssl https webview

我有一个网页,需要Mutual auth才能加载页面。 我使用ERROR_FAILED_SSL_HANDSHAKE获得onReceivedError()。在Webkit中打印日志“无法建立安全连接”。 我已经广泛搜索但找不到答案。有几个帖子但没有结论。 我尝试了here发布的所有3个解决方案。 可能起作用的解决方案是: - 解决方案1: 无论如何都使用ClientCertRequestHandler(它标记为隐藏,但显然仍然可用):

所以我修改了android.jar以包含内部API以覆盖onReceivedClientCertRequest() 但我没有在运行时获得回调。任何第三方浏览器都是如此。我尝试在标准浏览器中加载相同的网页。我在UI上收到一个回调,要求用户选择一个客户端证书。

所以似乎只有系统浏览器应用程序可以从Webkit获取onReceivedClientCertRequest()的回调。

对于iOS平台,Webview也无法直接加载网站。但是使用NSURL进行HTTPS连接, 将客户端证书保留在内存中一段时间​​,Webview可以成功加载此页面。

在Android上,我通过注册加载客户端和服务器证书的SSLSocketFactory成功设置了HTTPS通信。 我可以使用它进行REST API调用。但是,与iOS不同,我无法找到Android webview可以使用客户端证书进行相互身份验证的方式。

我认为平台应支持在Webview上进行相互认证,这是安全性的基本要求之一。这个问题有没有更新?

编辑1

根据我在下面给出的答案,我在Android 4.0到4.3上工作了。 Hoverer,现在在Android 4.4上,似乎WebViewClientClassicExt类本身被删除了。 知道在这种情况下可以做些什么吗?为什么Android不允许在webview中设置ClientCertificates?

1 个答案:

答案 0 :(得分:3)

所以我可以让这件事工作到4.3

  1. 在Android 4.0和4.1上,通过覆盖扩展WebViewClient的类的onReceivedClientCertRequest()
  2. 在4.2,4.3中,通过覆盖扩展WebViewClientClassicExt的类的onReceivedClientCertRequest()。
  3. 我设置私钥和证书ClientCertRequestHandler proceed()方法。

    Android需要4.4及更高版本的补丁

    <强> EDITED 解决方案uptil 4.3如下所示

    WebviewClientCustom.java

    public class WebViewClientCustom extends WebViewClient {
        private X509Certificate[] certificatesChain;
        private PrivateKey clientCertPrivateKey;
        private IWebViewCallbacks webviewCallbacks;
    
        public WebViewClientCustom(IWebViewCallbacks webviewCallbacks) {
            this.webviewCallbacks = webviewCallbacks;
        }
    
        public void onReceivedClientCertRequest(WebView paramWebView,
                ClientCertRequestHandler paramClientCertRequestHandler,
                String paramString) {
            PrivateKey localPrivateKey = this.clientCertPrivateKey;
            X509Certificate[] arrayOfX509Certificate = this.certificatesChain;
            paramClientCertRequestHandler.proceed(localPrivateKey,
                    arrayOfX509Certificate);
        }
    
        public void onReceivedError(WebView view, int errorCode,
                String description, String failingUrl) {
            webviewCallbacks.onReceivedError( view,  errorCode,
                     description,  failingUrl);
    
            super.onReceivedError( view,  errorCode,
                     description,  failingUrl);
        }
    
    
        public void setClientCertificate(PrivateKey paramPrivateKey,
                X509Certificate[] paramArrayOfX509Certificate) {
            this.clientCertPrivateKey = paramPrivateKey;
            this.certificatesChain = paramArrayOfX509Certificate;
        }
    
        public boolean shouldOverrideUrlLoading(WebView paramWebView,
                String paramString) {
            return webviewCallbacks.shouldOverrideUrlLoading(paramWebView,
                    paramString);
    
    
        }
    
        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            // TODO Auto-generated method stub
    
            webviewCallbacks.onPageStarted(view, url, favicon);
            super.onPageStarted(view, url, favicon);
        }
    
        @Override
        public void onPageFinished(WebView view, String url) {
            // TODO Auto-generated method stub
    
            webviewCallbacks.onPageFinished(view, url);
            super.onPageFinished(view, url);
        }
    
    }
    

    WebViewClientCustomExt.java

    public class WebViewClientCustomExt extends WebViewClientClassicExt {
        private X509Certificate[] certificatesChain;
        private PrivateKey clientCertPrivateKey;
        private IWebViewCallbacks webviewCallbacks;
    
        public WebViewClientCustomExt(IWebViewCallbacks webviewCallbacks) {
            this.webviewCallbacks = webviewCallbacks;
        }
    
        public void onReceivedClientCertRequest(WebView paramWebView,
                ClientCertRequestHandler paramClientCertRequestHandler,
                String paramString) {
            PrivateKey localPrivateKey = this.clientCertPrivateKey;
            X509Certificate[] arrayOfX509Certificate = this.certificatesChain;
            paramClientCertRequestHandler.proceed(localPrivateKey,
                    arrayOfX509Certificate);
        }
    
        public void onReceivedError(WebView view, int errorCode,
                String description, String failingUrl) {
            webviewCallbacks.onReceivedError( view,  errorCode,
                     description,  failingUrl);
    
            super.onReceivedError( view,  errorCode,
                     description,  failingUrl);
        }
    
    
    
        public void setClientCertificate(PrivateKey paramPrivateKey,
                X509Certificate[] paramArrayOfX509Certificate) {
            this.clientCertPrivateKey = paramPrivateKey;
            this.certificatesChain = paramArrayOfX509Certificate;
        }
    
        public boolean shouldOverrideUrlLoading(WebView paramWebView,
                String paramString) {
            return webviewCallbacks.shouldOverrideUrlLoading(paramWebView, paramString);
        }
    
        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            // TODO Auto-generated method stub
    
    
            webviewCallbacks.onPageStarted(view, url, favicon);
            super.onPageStarted(view, url, favicon);
        }
    
        @Override
        public void onPageFinished(WebView view, String url) {
            // TODO Auto-generated method stub
    
            webviewCallbacks.onPageFinished(view, url);
            super.onPageFinished(view, url);
        }
    }
    

    用法

     */
        private void setCertificateData() {
            // TODO Auto-generated method stub
            try {
                KeyStore clientCertKeystore = KeyStore.getInstance("pkcs12");
                String clientCertPkcsPassword = getPkcsPassword();
                byte[] pkcs12;
    
                pkcs12 = getAuthP12Data();
                ByteArrayInputStream pkcs12BAIS = new ByteArrayInputStream(pkcs12);
    
                clientCertKeystore.load(pkcs12BAIS,
                        clientCertPkcsPassword.toCharArray());
                String alias = (clientCertKeystore.aliases().nextElement());
                Certificate[] arrayOfCertificate = clientCertKeystore
                        .getCertificateChain(alias);
                X509Certificate[] arrayOfX509Certificate = new X509Certificate[arrayOfCertificate.length];
                for (int i = 0; i < arrayOfCertificate.length; i++) {
                    arrayOfX509Certificate[i] = (X509Certificate) arrayOfCertificate[i];
                }
                PrivateKey localPrivateKey = (PrivateKey) clientCertKeystore
                        .getKey(alias, clientCertPkcsPassword.toCharArray());
                if (android.os.Build.VERSION.SDK_INT <= 16) {
                    WebViewClientCustom webvviewClient = new WebViewClientCustom(
                            myWebViewClient);
                    webvviewClient.setClientCertificate(localPrivateKey,
                            arrayOfX509Certificate);
                    webView.setWebViewClient(webvviewClient);
    
                } else {
                    WebViewClientCustomExt webvviewClient = new WebViewClientCustomExt(
                            myWebViewClient);
                    webvviewClient.setClientCertificate(localPrivateKey,
                            arrayOfX509Certificate);
                    webView.setWebViewClient(webvviewClient);
                }
                // webView.getSettings().setJavaScriptEnabled(true);
    
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    
        }