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

有些时候由于Android系统的bug或者其他的原因,导致我们的webview不能验证通过我们的https证书,最明显的例子就是华为手机mate7升级到Android7.0后,手机有些网站打不开了,而更新了webview的补丁后就没问题了,充分说明系统的bug对我们混合开发webview加载https地址的影响是巨大的。那么我们怎么去解决这个问题呢?

476259802fdc9b1804af2887864090d0.png

首先我们去分析一下出现的原因

当webview加载https地址的时候,如果因为证书的问题出错的时候就会走onReceivedSslError()方法

webView.setWebViewClient(new WebViewClient() {

@Override

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

super.onReceivedSslError(view, handler, error);

}

}

而super.onReceivedSslError()默认是

de63f9ba1cd267aa0f4ce9440c7129a7.png

handler.cancel() 就是让加载的页面白屏,所有导致了如果webview校验证书存在异常,android在默认情况下会显示白屏,我们也可调用handler.proceed(),大多时候很多人都是这个处理,但是这也就意味着https证书失去了他存在的意义了。

d7ef98caadbad03575e960b45bf0144f.png

那么如果你的网站证书是正常的,但是因为系统的bug导致了加载异常,这时候就需要我们手动校验了。

其实我们是可以手动校验网站证书的sha256,如果异常之后校验sha256就执行handler.proceed(),失败就退出应用。

首先我们要获取网站的证书

利用谷歌浏览器,打开网址并且按下“F12”,打开开发者模式

3b0c0a179596d576b771ff15fa95762e.png

一步一步导出证书

79b13611362c823ad792fd58e889aed5.png

然后在打开sha256校验网址:http://www.atool.org/file_hash.php

a7d7ad097cac942b8a4105e86ef381c0.png

这样就获取到了证书的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

*

例如:

* 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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值