源码网商城,靠谱的源码在线交易网站 我的订单 购物车 帮助

源码网商城

Android webview手动校验https证书(by 星空武哥)

  • 时间:2020-04-25 11:24 编辑: 来源: 阅读:
  • 扫一扫,手机访问
摘要:Android webview手动校验https证书(by 星空武哥)
有些时候由于Android系统的bug或者其他的原因,导致我们的webview不能验证通过我们的https证书,最明显的例子就是华为手机mate7升级到Android7.0后,手机有些网站打不开了,而更新了webview的补丁后就没问题了,充分说明系统的bug对我们混合开发webview加载https地址的影响是巨大的。那么我们怎么去解决这个问题呢? [img]http://files.jb51.net/file_images/article/201709/2017090313173639.jpg[/img] 首先我们去分析一下出现的原因 当webview加载https地址的时候,如果因为证书的问题出错的时候就会走onReceivedSslError()方法
webView.setWebViewClient(new WebViewClient() { 
 
  @Override 
  public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { 
    super.onReceivedSslError(view, handler, error); 
  } 
} 
而super.onReceivedSslError()默认是 [img]http://files.jb51.net/file_images/article/201709/2017090313173640.png[/img] handler.cancel() 就是让加载的页面白屏,所有导致了如果webview校验证书存在异常,android在默认情况下会显示白屏,我们也可调用handler.proceed(),大多时候很多人都是这个处理,但是这也就意味着https证书失去了他存在的意义了。 [img]http://files.jb51.net/file_images/article/201709/2017090313173641.png[/img] 那么如果你的网站证书是正常的,但是因为系统的bug导致了加载异常,这时候就需要我们手动校验了。 其实我们是可以手动校验网站证书的sha256,如果异常之后校验sha256就执行handler.proceed(),失败就退出应用。 [b]首先我们要获取网站的证书[/b] 利用谷歌浏览器,打开网址并且按下“F12”,打开开发者模式 [img]http://files.jb51.net/file_images/article/201709/2017090313173642.png[/img] 一步一步导出证书 [img]http://files.jb51.net/file_images/article/201709/2017090313173643.png[/img] 然后在打开sha256校验网址:http://www.atool.org/file_hash.php 或[url=http://tools.jb51.net/password/sha_encode]http://tools.jb51.net/password/sha_encode[/url] [img]http://files.jb51.net/file_images/article/201709/2017090313173644.png[/img] 这样就获取到了证书的sha256的值,写了一个工具类
  /**
   * SSL证书错误,手动校验https证书
   *
   * @param cert   https证书
   * @param sha256Str sha256值
   * @return true通过,false失败
   */
  public static boolean isSSLCertOk(SslCertificate cert, String sha256Str) {
    byte[] SSLSHA256 = hexToBytes(sha256Str);
    Bundle bundle = SslCertificate.saveState(cert);
    if (bundle != null) {
      byte[] bytes = bundle.getByteArray("x509-certificate");
      if (bytes != null) {
        try {
          CertificateFactory cf = CertificateFactory.getInstance("X.509");
          Certificate ca = cf.generateCertificate(new ByteArrayInputStream(bytes));
          MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
          byte[] key = sha256.digest(((X509Certificate) ca).getEncoded());
          return Arrays.equals(key, SSLSHA256);
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    }
    return false;
  }

  /**
   * hexString转byteArr
   * <p>例如:</p>
   * hexString2Bytes("00A8") returns { 0, (byte) 0xA8 }
   *
   * @param hexString
   * @return 字节数组
   */
  public static byte[] hexToBytes(String hexString) {

    if (hexString == null || hexString.trim().length() == 0)
      return null;

    int length = hexString.length() / 2;
    char[] hexChars = hexString.toCharArray();
    byte[] bytes = new byte[length];
    String hexDigits = "0123456789abcdef";
    for (int i = 0; i < length; i++) {
      int pos = i * 2; // 两个字符对应一个byte
      int h = hexDigits.indexOf(hexChars[pos]) << 4; // 注1
      int l = hexDigits.indexOf(hexChars[pos + 1]); // 注2
      if (h == -1 || l == -1) { // 非16进制字符
        return null;
      }
      bytes[i] = (byte) (h | l);
    }
    return bytes;
  }
然后在onReceivedSslError()判断
webView.setWebViewClient(new WebViewClient() {
 @Override
 public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
  super.onReceivedSslError(view, handler, error);
  if (error.getPrimaryError() == SslError.SSL_INVALID) {
   // 如果手动校验sha256成功就允许加载页面
   if (SSLCertUtil.isSSLCertOk(error.getCertificate(), "6683c9584b8287ec3a50e312f4a540c79938aaeb76bd02e40a9ca037ee5d24f4")) {
    handler.proceed();
   } else {
    try {
     new AlertDialog.Builder(MainActivity.this)
       .setTitle("警告")
       .setMessage("证书校验失败")
       .setPositiveButton("退出", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
         System.exit(0);
         dialog.dismiss();
        }
       }).show();
    } catch (Exception e) {
     e.printStackTrace();
    }
   }
  } else {
   handler.cancel();
  }
 }
});
这里我们只是真对SslError.SSL_INVALID进行了判断,可能还有其他情况,根据自己的情况判定。
/**
 * The certificate is not yet valid
 */
public static final int SSL_NOTYETVALID = 0;
/**
 * The certificate has expired
 */
public static final int SSL_EXPIRED = 1;
/**
 * Hostname mismatch
 */
public static final int SSL_IDMISMATCH = 2;
/**
 * The certificate authority is not trusted
 */
public static final int SSL_UNTRUSTED = 3;
/**
 * The date of the certificate is invalid
 */
public static final int SSL_DATE_INVALID = 4;
/**
 * A generic error occurred
 */
public static final int SSL_INVALID = 5;
这样就完成了手动校验https证书校
  • 全部评论(0)
联系客服
客服电话:
400-000-3129
微信版

扫一扫进微信版
返回顶部