关于webview加载https的正确使用方式

关于webview加载https的正确使用方式

头几天同事遇到webview加载https出现空白页面的情况,简单查了一下发现是因为所使用的证书没有本地授信,同样的网址复制到浏览器中会弹出一个对话框提示查看或者继续,而webview中却没有,网上的方式就是在webviewclient中重写onReceivedSslError这个方法,然后调用handler.proceed();授信就可以,不过这存在一个问题就是没有对加载的https证书进行校验,就直接通过了,容易受到攻击或者代理拦截之类的,所有加上了一层证书的校验,具体的方式看代码:

@Override
  public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
      SslCertificate certificate = error.getCertificate();
      String cName = certificate.getIssuedBy().getCName();
      String uName = certificate.getIssuedTo().getOName();
      if(HttpsUtils.checkSslCertificate(certificate)&&
              cName.equals(getResources().getString(R.string.ssl_issueby_name))&&
              uName.equals(getResources().getString(R.string.company_name))){
          handler.proceed();
      }
  }

原理就是通过SslError取到https的证书,然后分别取使用者和颁发者的名字,进行对比,同时也会对比这个证书与本地的一个证书的职位是否相同。通过方法HttpsUtils.checkSslCertificate():

public static boolean checkSslCertificate(SslCertificate certificate) {
        Bundle bundle = SslCertificate.saveState(certificate);
        byte[] bytes = bundle.getByteArray("x509-certificate");
        if (bytes != null) {
            try {
                CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
                Certificate ce = certificateFactory.generateCertificate(new ByteArrayInputStream(bytes));
                MessageDigest instance = MessageDigest.getInstance("SHA-256");
                byte[] digest = instance.digest(ce.getEncoded());
                byte[] local = instance.digest(localCertificate.getEncoded());
                return Arrays.equals(local, digest);
            } catch (Exception e) {
            }
        }
        return false;
    }

其中的localCertificate就是通过读取本地文件而获得的一个证书对象,对比两个证书的指纹是否相同。HttpsUtils这个类是使用Okhttp进行请求时,初始化sslfactory和trustmanager这两个对象的,在获取TrustManager时会读取本地文件生成一个证书,赋值就可以了:

一共有三重校验,证书指纹,颁发者和使用者,基本可以保证安全。

你可能感兴趣的:(关于webview加载https的正确使用方式)