javax.net.ssl.SSLHandshakeException: Chain validation failed 异常解决
javax.net.ssl.SSLHandshakeException: Chain validation failed 异常解决描述在项目中使用RxJava,OkHttp和Retrofit封装的网络请求,再测试时一切正常,但修改为https的线上正式服务器后就报了异常:javax.net.ssl.SSLHandshakeException: Chain validation failed...
javax.net.ssl.SSLHandshakeException: Chain validation failed 异常解决
描述
在项目中使用RxJava,OkHttp和Retrofit封装的网络请求,再测试时一切正常,但修改为https的线上正式服务器后就报了异常:
javax.net.ssl.SSLHandshakeException: Chain validation failed
初次打开时会系统会有提示:
![](https://i-blog.csdnimg.cn/blog_migrate/03a154a734ee7945d99598d3348f944d.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/5110f3cf67b1de06718f2f677524bb1d.jpeg)
探究
作为一名合格的面向百度编程工程师,我熟练的打开了搜索引擎,找到了鸿洋大佬的 Android Https相关完全解析 当OkHttp遇到Https 博客。发现了以下内容
OkHttp 默认是支持 Https 协议的网站,但前提条件是:支持 Https 的网站证书都是由 CA 机构版本的证书。
与后台沟通后说证书没问题,是通过 CA 认证颁布的,之后通过浏览器打开了这个网址:
通过Chrome浏览器打开网址,有个锁头的图标,也说明了证书是有效的。这就很奇怪,接下来再点击证书
看一下具体的证书信息
可以看到,证书的有效期是2019/12/26到2020/12/05,证书是有有效期的,那么和这个有效期进行对比的就应该是设备时间,我恍然大悟,回头检查了一下手机设置的时间,发现还是2019/6/1日,这时我将系统时间修改到证书有效期内的时间,就可以正常访问了。这样看来,证书有效期是和访问设备的系统时间有关,也是https的SSL验证机制使然。
解决方法一:
解决方法很简单,检查一下设备系统时间是否在证书有效期内,若没有就改到有效期即可(一般系统时间调整为跟网络一致)。
解决方法二:跳过https验证机制
问题解决了,只要将手机系统时间改为当前时间即可了。如果没有其他特殊需求,看到这里就可以结束了。
接下来就是特殊需求,为了某些SDK的算法验证,系统时间是我特意设置成2019年6月1号的,就不能用当前时间,所以以上方法对我来说没用,但既然知道了原理,那么解决起来就方便了。既然是Https的SSL验证,那么通过okhttp跳过这个验证不就好了,在网上查了一下,发现了跳过验证的写法:
在构建Okhttps时,自定义SSL验证流程,信任一切证书:
//自定义SS验证相关类
private static class TrustAllCerts implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
private static class TrustAllHostnameVerifier implements HostnameVerifier {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
}
private static SSLSocketFactory createSSLSocketFactory() {
SSLSocketFactory ssfFactory = null;
try {
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, new TrustManager[]{new TrustAllCerts()}, new SecureRandom());
ssfFactory = sc.getSocketFactory();
} catch (Exception e) {
}
return ssfFactory;
}
构建Okhttp时,使用它:
okBuilder.sslSocketFactory(createSSLSocketFactory());
okBuilder.hostnameVerifier(new TrustAllHostnameVerifier());
return okBuilder.build();
这样就解决了我的问题,但缺点是信任任何网址,无论是否有证书或者在证书有效期内,我的项目是公司内部网站,小伙伴们如果使用这个方法请斟酌一下。
有关Https知识,也可以看看扔物线的https讲解视频
更多推荐
所有评论(0)