Trust Certificate Authority in WebView loadUrl()

2019-02-26 03:57发布

From a result of security scan program, I have a need to restrict the Certificate Authorities the app trusts.

The scan result points out the line at webView.loadUrl("https://example.com/page");. I see how I can create a SslSocketFactory that uses my TrustManager, but I don't see an API in WebView that allows me to set that.

https://developer.android.com/training/articles/security-ssl.html#UnknownCa

What are some possible ways to achieve this?

1条回答
劳资没心,怎么记你
2楼-- · 2019-02-26 04:27

I think WebViewClient 's onReceivedSslError method will be a good entry point.

First of all, follow the exact same snippet from https://developer.android.com/training/articles/security-ssl.html#UnknownCa to prepare TrustManager.

    TrustManagerFactory tmf = null;

    private void initTrustStore() throws
            java.security.cert.CertificateException, FileNotFoundException,
            IOException, KeyStoreException, NoSuchAlgorithmException {

        // Create a KeyStore containing our trusted CAs
        String keyStoreType = KeyStore.getDefaultType();
        KeyStore trustedKeyStore = KeyStore.getInstance(keyStoreType);
        trustedKeyStore.load(null, null);

        CertificateFactory cf = CertificateFactory.getInstance("X.509");

        InputStream caInput = new BufferedInputStream(
                    getResources().getAssets().open("ca.crt"));
            Certificate ca;
            try {
                ca = cf.generateCertificate(caInput);
                Log.d(TAG, "ca-root DN=" + ((X509Certificate) ca).getSubjectDN());
            }
            finally {
                caInput.close();
            }
            trustedKeyStore.setCertificateEntry("ca", ca);

        // Create a TrustManager that trusts the CAs in our KeyStore
        String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
        tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
        tmf.init(trustedKeyStore);

    }

Then, extends custom WebViewClient class, checking snippet from https://stackoverflow.com/a/6379434/1099884

private class CheckServerTrustedWebViewClient extends WebViewClient{
    public void onReceivedSslError(WebView view, final SslErrorHandler handler, SslError error) {
        Log.d(TAG, "onReceivedSslError");
        boolean passVerify = false;

        if(error.getPrimaryError() == SslError.SSL_UNTRUSTED){
            SslCertificate cert = error.getCertificate();
            String subjectDN = cert.getIssuedTo().getDName();
            Log.d(TAG, "subjectDN: "+subjectDN);
            try{
                Field f = cert.getClass().getDeclaredField("mX509Certificate");
                f.setAccessible(true);
                X509Certificate x509 = (X509Certificate)f.get(cert);

                X509Certificate[] chain = {x509};
                for (TrustManager trustManager: tmf.getTrustManagers()) {
                    if (trustManager instanceof X509TrustManager) {
                        X509TrustManager x509TrustManager = (X509TrustManager)trustManager;
                        try{
                            x509TrustManager.checkServerTrusted(chain, "generic");
                            passVerify = true;break;
                        }catch(Exception e){
                            Log.e(TAG, "verify trustManager failed", e);
                            passVerify = false;
                        }
                    }
                }
                Log.d(TAG, "passVerify: "+passVerify);
            }catch(Exception e){
                Log.e(TAG, "verify cert fail", e);
            }
        }
        if(passVerify == true)handler.proceed();
        else handler.cancel();

    }       

}

Finally, set the CheckServerTrustedWebViewClient to WebView

webView.setWebViewClient(new CheckServerTrustedWebViewClient());

However, there is one problem. The prepared CA certificate is the exact one sign the server one (intermediate-CA NOT root CA). Only provide root CA certificate will not work. Isn't TrustManager can download server certificate chain on runtime? Any suggestion?

查看更多
登录 后发表回答