javax.net.ssl.SSLHandshakeException: Chain validation failed 异常解决

描述

在项目中使用RxJava,OkHttp和Retrofit封装的网络请求,再测试时一切正常,但修改为https的线上正式服务器后就报了异常:

javax.net.ssl.SSLHandshakeException: Chain validation failed

初次打开时会系统会有提示:

探究

作为一名合格的面向百度编程工程师,我熟练的打开了搜索引擎,找到了鸿洋大佬的 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讲解视频

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐