Android中webview.loadUrl()出现错误 - 未找到证书路径的信任锚点

26

我有一个用于加载网址的 webview,但是它不起作用。

看看我的代码:

public class MainActivity extends AppCompatActivity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    WebView wv = (WebView) findViewById(R.id.webView);

    //Log.d("rudyy", "aqui");
    wv.loadUrl("https://tripulanteaims.tam.com.br/wtouch/wtouch.exe/index");
    //Log.d("rudyy", "fim");


  }
}

执行此代码时,Android 返回以下错误:

Failed to validate the certificate chain, error: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

请帮我一下。

3个回答

53
创建一个 WebViewClient:
private class WvClient extends WebViewClient 
{
    @Override
    public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError er) {
        handler.proceed(); 
        // Ignore SSL certificate errors
    }
}

并将初始化的 WebViewClient (“WvClient”)设置为您的 WebView(在这种情况下是“wv”):

wv.setWebViewClient(new WvClient());

或者一行内:

 wv.setWebViewClient(new WebViewClient() {@Override public void onReceivedSslError(WebView v, SslErrorHandler handler, SslError er){ handler.proceed(); }});

2
@Override public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error){ handler.proceed(); } });将上述代码添加到您的Android应用程序中,以便在加载网页时忽略SSL错误。 - tyoc213
20
这只是忽略所有 SSL 错误。绝对不是一个好的解决方案。 - Mavamaarten
6
为什么我的浏览器显示我使用的网站有一个好的证书,但为什么它仍然会出现 SSL 错误? - Michael

12

我正在处理这个问题,坦率地说,允许中间人攻击是不可行的。以下是一种更清洁的解决方案,支持固定证书锁定。将证书保存到您的原始资源文件夹中。
注意:遗憾的是,当您调用getCertificate()时,SSLError会给我们一个SslCertificate。SslCertificate有点无用。它的公共API不允许您验证公钥,仅创建日期,过期日期,签发给,签发者等。但是,如果您打开此类,您将看到一个未公开的X509Certificate成员变量。我不知道为什么要采取这种设计决策。但是,有一个获取Bundle的API,而该X509 Certificate成员变量存储在其中。因此,我们通过这种方式进行访问,因为证书具有更多有用的方法。

@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
    SslCertificate sslCertificateServer = error.getCertificate();
    Certificate pinnedCert = getCertificateForRawResource(R.raw.your_cert, mContext);
    Certificate serverCert = convertSSLCertificateToCertificate(sslCertificateServer);

    if(pinnedCert.equals(serverCert)) {
        handler.proceed();
    } else {
        super.onReceivedSslError(view, handler, error);
    }
}

public static Certificate getCertificateForRawResource(int resourceId, Context context) {
    CertificateFactory cf = null;
    Certificate ca = null;
    Resources resources = context.getResources();
    InputStream caInput = resources.openRawResource(resourceId);

    try {
        cf = CertificateFactory.getInstance("X.509");
        ca = cf.generateCertificate(caInput);
    } catch (CertificateException e) {
        Log.e(TAG, "exception", e);
    } finally {
        try {
            caInput.close();
        } catch (IOException e) {
            Log.e(TAG, "exception", e);
        }
    }

    return ca;
}

public static Certificate convertSSLCertificateToCertificate(SslCertificate sslCertificate) {
    CertificateFactory cf = null;
    Certificate certificate = null;
    Bundle bundle = sslCertificate.saveState(sslCertificate);
    byte[] bytes = bundle.getByteArray("x509-certificate");

    if (bytes != null) {
        try {
            CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
            Certificate cert = certFactory.generateCertificate(new ByteArrayInputStream(bytes));
            certificate = cert;
        } catch (CertificateException e) {
            Log.e(TAG, "exception", e);
        }
    }

    return certificate;
}

嗨,Ryan... 我们只需要覆盖这些方法吗? - RickON
@RickON 扩展 WebViewClient 并覆盖 onReceivedSslError 方法。 - Ryan Newsom
请注意,如果您使用证书固定功能,并且您固定的证书发生变化,则您的应用程序将无法正常工作。这是需要考虑的一个问题... - Ryan Newsom
@MehulRanpara 这个陈述的基础是什么? - Johnny Five

3

这是正确的解决方案,通过实施以下代码,Google将会批准您的应用程序:

@Override
public void onReceivedSslError(WebView view, final SslErrorHandler handler, SslError error) {
    // for SSLErrorHandler
    final AlertDialog.Builder builder = new AlertDialog.Builder(context);
    builder.setMessage(R.string.notification_error_ssl_cert_invalid);
    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();
}

如果您使用以下代码,那么在调试时它将起作用,但谷歌将拒绝您的应用程序:

private class WvClient extends WebViewClient 
{
    @Override
    public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError er) {
        handler.proceed(); 
        // Ignore SSL certificate errors
    }
}

我可以确认,如果您发布应用程序,谷歌Play不会接受最受欢迎的答案。当我提交应用程序时,我收到了以下消息:我们审查了APPNAME,包名为APP.PACKAGE,并发现您的应用程序使用包含用户安全漏洞的软件。SSL错误处理程序。感谢您提供有效/良好的解决方案。 - Slamit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接