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

kiz8lqtg  于 2023-02-14  发布在  Android
关注(0)|答案(5)|浏览(152)

android上的WebView控件是否支持SSL?
我正在尝试加载一个使用可信ssl证书的网页,但WebView只是白色。
有什么建议吗?

rvpgvaaj

rvpgvaaj1#

不是Maven,只是我能在网上找到的。据我所知,WebView确实支持SSL,但是,空白屏幕表明WebView不相信证书是有效的。这可能发生在自签名证书或没有在Android中设置的根授权证书上(完全有效的cert不验证).在任何情况下,如果你使用froyo或更好的,你可以尝试类似的东西:

import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.webkit.SslErrorHandler;
import android.net.http.SslError;

...

engine = (WebView) findViewById(R.id.my_webview);
engine.setWebViewClient(new WebViewClient() {

    @Override
    public void onReceivedSslError (WebView view, SslErrorHandler handler, SslError error) {
        handler.proceed();
    }
});
xa9qqrwz

xa9qqrwz2#

要根据更新的安全策略正确处理SSL证书验证,请更改代码,以便在服务器提供的证书符合预期时调用SslErrorHandler.proceed(),否则调用SslErrorHandler.cancel()。
例如,我添加了一个提醒对话框,使用户已确认,似乎谷歌不再显示警告。

@Override
    public void onReceivedSslError(WebView view, final SslErrorHandler handler, SslError error) {
    final AlertDialog.Builder builder = new AlertDialog.Builder(view.getContext());
    String message = "SSL Certificate error.";
        switch (error.getPrimaryError()) {
            case SslError.SSL_UNTRUSTED:
                message = "The certificate authority is not trusted.";
                break;
            case SslError.SSL_EXPIRED:
                message = "The certificate has expired.";
                break;
            case SslError.SSL_IDMISMATCH:
                message = "The certificate Hostname mismatch.";
                break;
            case SslError.SSL_NOTYETVALID:
                message = "The certificate is not yet valid.";
                break;
        }
        message += " Do you want to continue anyway?";

        builder.setTitle("SSL Certificate Error");
        builder.setMessage(message);
    builder.setPositiveButton("continue", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            handler.proceed();
        }
    });
    builder.setNegativeButton("cancel", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            handler.cancel();
        }
    });
    final AlertDialog dialog = builder.create();
    dialog.show();
}

在此更改之后,将不会显示警告。

chhkpiq4

chhkpiq43#

Google Play拒绝了我的应用程序,然后我这样做了...

@Override
    public void onReceivedSslError(WebView view, final SslErrorHandler handler, SslError error) {

        try {

            //Get the X509 trust manager from your ssl certificate
            X509TrustManager trustManager = mySslCertificate.getX509TrustManager();

            //Get the certificate from error object
            Bundle bundle = SslCertificate.saveState(error.getCertificate());
            X509Certificate x509Certificate;
            byte[] bytes = bundle.getByteArray("x509-certificate");
            if (bytes == null) {
                x509Certificate = null;
            } else {
                CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
                Certificate cert = certFactory.generateCertificate(new ByteArrayInputStream(bytes));
                x509Certificate = (X509Certificate) cert;
            }
            X509Certificate[] x509Certificates = new X509Certificate[1];
            x509Certificates[0] = x509Certificate;

            // check weather the certificate is trusted
            trustManager.checkServerTrusted(x509Certificates, "ECDH_RSA");

            Log.e(TAG, "Certificate from " + error.getUrl() + " is trusted.");
            handler.proceed();
        } catch (Exception e) {
            Log.e(TAG, "Failed to access " + error.getUrl() + ". Error: " + error.getPrimaryError());
            final AlertDialog.Builder builder = new AlertDialog.Builder(WebViewActivity.this);
            String message = "SSL Certificate error.";
            switch (error.getPrimaryError()) {
                case SslError.SSL_UNTRUSTED:
                    message = "The certificate authority is not trusted.";
                    break;
                case SslError.SSL_EXPIRED:
                    message = "The certificate has expired.";
                    break;
                case SslError.SSL_IDMISMATCH:
                    message = "The certificate Hostname mismatch.";
                    break;
                case SslError.SSL_NOTYETVALID:
                    message = "The certificate is not yet valid.";
                    break;
            }
            message += " Do you want to continue anyway?";

            builder.setTitle("SSL Certificate Error");
            builder.setMessage(message);
            builder.setPositiveButton("continue", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    handler.proceed();
                }
            });
            builder.setNegativeButton("cancel", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    handler.cancel();
                }
            });
            final AlertDialog dialog = builder.create();
            dialog.show();
        }
    }

进行上述更改后,Google Play接受了我的APK
要生成您的ssl信任管理器,请检查此answer

xqnpmsa8

xqnpmsa84#

对戈夫斯基的解决方案做一点修改:

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

                        try {
                            X509Certificate cert[] = new X509Certificate[1];
                            boolean isTrusted = false;
                            if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.Q) {
                                // for andoid sdk < version 29, the SslCertificate does not
                                // contain a public method for getting the x509Certificate. The
                                // following code is the trick used to get the x509Certificate
                                // from the SslCertificate
                                Bundle bundle = SslCertificate.saveState(error.getCertificate());
                                byte[] bytes = bundle.getByteArray("x509-certificate");
                                if (bytes == null) {
                                 } else {
                                    try {
                                        CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
                                        cert[0] = (X509Certificate)certFactory.generateCertificate(new ByteArrayInputStream(bytes));
                                     } catch (CertificateException e) {
                                        cert[0] = null;
                                    }
                                }
                            } else {
                                // for andoid sdk >= version 29, the SslCertificate contains
                                // a method for getting the x509Certificate
                                cert[0] = error.getCertificate().getX509Certificate();
                            }
                            if (cert[0] != null) {
                                TrustManagerFactory tmfactory = null;
                                tmfactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
                                tmfactory.init(CoreInternal.getTrustStore());
                                for (TrustManager trustManager : tmfactory.getTrustManagers()) {
                                    if (trustManager instanceof X509TrustManager) {
                                        try {
                                            ((X509TrustManager) trustManager).checkServerTrusted(cert, "RSA");
                                            isTrusted = true;
                                            break;
                                        } catch (CertificateException e) {
                                        }
                                    }
                                }
                                if (isTrusted) handler.proceed();
                                else {
                                    Core.getLog().e(TAG, activity.getString(R.string.errorUntrustedServer)
                                            + ": " + error.getUrl());
                                    handler.cancel();
                                }
                            }
                        } catch (NoSuchAlgorithmException | KeyStoreException e) {
                            handler.cancel();
                        }
                    }
                });

收到SSL错误后,此例程将根据我的私有信任存储验证服务器证书,其中该存储是通过我的方法CoreInternal.getTrustStore获得的(),它是一个Java密钥存储库,包含我的应用程序的私有受信任证书。如果要使用此代码,则必须提供自己的等效代码,以获取自己的私有密钥存储库,用于存储自己的个人受信任证书。对于android sdk〈版本29,你必须做一个技巧来从你从“错误”中获得的SslCertificate中获得x509证书。开始,在android sdk版本29中,SslCertificate提供了一个从SslCertificate中获得x509certifact的公共方法。在这段代码中,我也有一个围绕Android Log类的 Package 类,所以如果你想使用它,您需要修改它以满足您自己的要求。
我之所以提供这个解决方案,是因为从Gowski的代码中我并不清楚验证证书所使用的密钥库是什么。尝试验证Android内部信任库是没有意义的。因为你得到这个错误是因为服务器证书不受信任使用系统信任存储.他的代码没有解释mySslCertificate.getX509TrustManager()正在执行与用于验证的信任存储区相同的操作。

r8uurelv

r8uurelv5#

您必须启用webview设置才能查看基于SSL的网站:

webView.getSetting().setDomStorageEnable(true);

相关问题