问题描述

  在公司的项目中遇到个比较烦人的错误,牢骚就不多说了,下面我们直接步入正题。主要因为在进行利用Okhttp访问图片的时候出现的问题,这里的图片是用Glide加载,当然Glide也是用Okhttp注册过的,具体方法去了解Glide.register()方法,那么这里出现SSL握手错误的原因到底在哪?为了解决这个问题,我搜集了一些解决方案和原因,就都罗列到下面了。

Tips:下面的方案仅适用于安卓移动端,其他开发人员请酌情参考

错误日志

  这是出现SSL握手出现错误的主要日志,如果你也报了类似下面的错误,那么后面解决方案可能就很适合你

javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.at com.android.org.conscrypt.ConscryptFileDescriptorSocket.startHandshake(ConscryptFileDescriptorSocket.java:219)at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.java:302)at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.java:270)at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:162)at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:257)at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:135)at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:114)at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:126)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:200)at okhttp3.RealCall.execute(RealCall.java:77)at hik.business.ga.common.imageloader.OkHttpStreamFetcher.loadData(OkHttpStreamFetcher.java:63)at hik.business.ga.common.imageloader.OkHttpStreamFetcher.loadData(OkHttpStreamFetcher.java:36)at com.bumptech.glide.load.model.ImageVideoModelLoader$ImageVideoFetcher.loadData(ImageVideoModelLoader.java:70)at com.bumptech.glide.load.model.ImageVideoModelLoader$ImageVideoFetcher.loadData(ImageVideoModelLoader.java:53)at com.bumptech.glide.load.engine.DecodeJob.decodeSource(DecodeJob.java:170)at com.bumptech.glide.load.engine.DecodeJob.decodeFromSource(DecodeJob.java:128)at com.bumptech.glide.load.engine.EngineRunnable.decodeFromSource(EngineRunnable.java:127)at com.bumptech.glide.load.engine.EngineRunnable.decode(EngineRunnable.java:106)at com.bumptech.glide.load.engine.EngineRunnable.run(EngineRunnable.java:58)at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:457)at java.util.concurrent.FutureTask.run(FutureTask.java:266)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)at java.lang.Thread.run(Thread.java:784)at com.bumptech.glide.load.engine.executor.FifoPriorityThreadPoolExecutor$DefaultThreadFactory$1.run(FifoPriorityThreadPoolExecutor.java:118)
原因1:Https访问,但证书过期

  如果是利用https进行访问,但出现了报错很大的原因就是因为证书已经过期,那么对于这种情况,我们可以有下面几步的解决方案。

  解决方案1:更新证书

  询问或者查看服务器端的证书是否过期,如果过期了,那么服务器有没有重新申请证书进行验证。所以第一个解决方案就是让服务器端申请证书进行验证。

  解决方案2:更新测试机时间

  如果解决方案1那里没有什么问题,这时候就需要看看你的测试机时间是不是不太对劲。就是时间比证书提交的时间早,那么就有很大可能出现这个错误,所以这里把时间更新就行。

  解决方案3:信任所有证书

  说起来作为移动开发人员实在是不太想用到第三个解决方案,这在一定程度上代表了无奈和妥协,那就是无条件信任或者说是忽略掉所有的证书,这样自然就访问通过,都不需要握手就过了,但其实也在一定程度上使https协议和http没有丝毫差别,毕竟连SSL的边都不用擦,废话不多说,信任所有证书的方法附上:

  简单版:
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;public class AllowX509TrustManager implements X509TrustManager {private static TrustManager[] trustManagers;private static final X509Certificate[] _AcceptedIssuers = newX509Certificate[] {};@Overridepublic void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}@Overridepublic void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}@Overridepublic X509Certificate[] getAcceptedIssuers() {return _AcceptedIssuers;}public boolean isClientTrusted(X509Certificate[] chain) {return true;}public boolean isServerTrusted(X509Certificate[] chain) {return true;}public static void allowAllSSL() {HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {@Overridepublic boolean verify(String arg0, SSLSession arg1) {// TODO Auto-generated method stubreturn true;}});SSLContext context = null;if (trustManagers == null) {trustManagers = new TrustManager[] { new AllowX509TrustManager() };}try {context = SSLContext.getInstance("SSL");context.init(null, trustManagers, new SecureRandom());} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (KeyManagementException e) {e.printStackTrace();}HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());}
}

  如上在Appliaction中调用这个类的allowAllSSL()方法,也就是调用AllowX509TrustManager.allowAllSSL();就会在这个Appliaction中建立信任。

  Okhttp配合版:
 private OkHttpClient getHttpsClient() {OkHttpClient.Builder okhttpClient = new OkHttpClient().newBuilder();//信任所有服务器地址okhttpClient.hostnameVerifier(new HostnameVerifier() {@Overridepublic boolean verify(String s, SSLSession sslSession) {//设置为truereturn true;}});//创建管理器TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {@Overridepublic void checkClientTrusted(java.security.cert.X509Certificate[] x509Certificates,String s) throws java.security.cert.CertificateException {}@Overridepublic void checkServerTrusted(java.security.cert.X509Certificate[] x509Certificates,String s) throws java.security.cert.CertificateException {}@Overridepublic java.security.cert.X509Certificate[] getAcceptedIssuers() {return new java.security.cert.X509Certificate[] {};}} };try {SSLContext sslContext = SSLContext.getInstance("TLS");sslContext.init(null, trustAllCerts, new java.security.SecureRandom());//为OkHttpClient设置sslSocketFactoryokhttpClient.sslSocketFactory(sslContext.getSocketFactory());} catch (Exception e) {e.printStackTrace();}return okhttpClient.build();}

其中关于添加sslSocketFactory这个方法在Okhttp新版本里的写法是:

okhttpClient.sslSocketFactory(sslContext.getSocketFactory(),trustAllCerts);
  解决方案4:更新证书信任

  看到这里,你应该还是比较喜欢挑战的一个程序小伙,那么我只好将失传已久的更新证书的方法告诉尔等,望各位好生珍惜。这里其实是基于你已经拿到证书了,那么你只是忘了更新,很简单,这里把它跟新上就行。
  将证书文件放置在assets目录(或者其他能读取到证书的目录),在创建OkhttpClient对象时sslSocketFactory()将该证书信息添加。仅仅信任你更新的证书就行,这样https还是我们熟悉的样子。

private SSLContext getSLLContext() {SSLContext sslContext = null;try {CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");InputStream certificate = mContext.getAssets().open("jiuge-j1.crt");KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());keyStore.load(null);String certificateAlias = Integer.toString(0);keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate));sslContext = SSLContext.getInstance("TLS");final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());trustManagerFactory.init(keyStore);sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());} catch (CertificateException e) {e.printStackTrace();} catch (KeyStoreException e) {e.printStackTrace();} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (KeyManagementException e) {e.printStackTrace();}return sslContext;}

使用Okhttp时进行设置就行

OkHttpClient httpClient = new OkHttpClient().newBuilder().sslSocketFactory(getSLLContext().getSocketFactory()).build();

同样在Okhttp新版本里的写法是,当然这里你需要参考解决方法3,创建管理器trustAllCerts:

okhttpClient.sslSocketFactory(getSLLContext().getSocketFactory(),trustAllCerts);

这里的方法仅仅适用于Okhttp,如果是其他情况可用参考下面两篇文章
为你的android App实现自签名的ssl证书(https)
android https遇到自签名证书/信任证书

原因2:利用Http访问,但服务端却是需要https验证

  这个原因没错就是我导致错误的主要原因之一,因为是使用http进行访问,却报了个SSL的握手错误,这让我沉思了许久。因为http它就没用到SSL协议啊,最终发现是服务器端返回的链接中是夹带ssl证书的,且在服务器端需要进行一个ssl校验,也就是是不管怎么样,我服务器就是要https,其他什么都不行,于是这里我迫于淫威,将所有的http访问变成的https进行访问,当然有一部分原因是因为公司网络环境比较特殊,这里就不予赘述,然后添加上了所有证书信任就可以了。

那么到此就是对SSL访问的一些原因分析和解决方案,希望能给诸君带来收获。

关于SSL握手的错误解决相关推荐

  1. 深入解析:如何修复SSL / TLS握手失败错误(中)

    上篇内容我们首先介绍什么是SSL / TLS握手的概念和简单的流程概述,为的就是让有的童鞋们能够更好地理解.那么接下来呢我们将介绍SSL/ TLS握手失败和错误(SSL握手错误)的所有可能原因以及谁可 ...

  2. 深入解析:如何修复SSL / TLS握手失败错误(上)

    接下来的三篇内容我们来讨论SSL / TLS握手失败错误及其修复方法. 针对互联网用户和网站所有者的SSL / TLS握手失败错误修复程序 像许多SSL错误消息一样,SSL握手错误可以从客户端和服务器 ...

  3. PySpider HTTP 599: SSL certificate problem错误的解决方法

    PySpider HTTP 599: SSL certificate problem错误的解决方法 参考文章: (1)PySpider HTTP 599: SSL certificate proble ...

  4. 解决 Let’s Encrypt SSL 证书配置错误

    解决 Let's Encrypt SSL 证书配置错误"DNS problem: NXDOMAIN looking up A for xxx.com" 一.问题:Let's Enc ...

  5. java 输出ssl握手信息_使用Java的SSL握手错误

    我正在尝试使用SSL证书将Java客户端与JMX服务器连接 . 但遗憾的是,此连接会产生SSL握手错误 . 当我尝试使用 -Djavax.net.debug=all 标志进行调试时,我在java客户端 ...

  6. SVN SSL错误解决

     eclipse连接svn服务器的时候报SSL 等错误 解决办法: 依据下面的地址: C:\Users\#your usrname#\AppData\Roaming\Subversion\auth\ ...

  7. wget通过代理下载之错误解决1(Proxy tunneling failed: Forwarding failureUnable to establish SSL connection.)

    wget通过代理下载之错误解决1(Proxy tunneling failed: Forwarding failureUnable to establish SSL connection.) 文章目录 ...

  8. gdc服务器ssl证书不一致,如何解决SSL证书不匹配错误

    如何解决 当终端用户访问错误的域名,而不是已经安装SSL证书的真实域名时,就是认为这是SSL证书错误.如果用户分析错误,那么他们可以理解,起源域名是他访问以外的其他域名.根据不同的网页浏览器政策,我们 ...

  9. SSL证书常见错误及解决办法

    SSL错误是一种常见的网络通信问题,可能会对用户的网络使用造成一定的影响.解决SSL错误的方法相对比较简单,但用户需要保持高度警惕,远离那些不安全的网站,以保护自己的网络安全和隐私.同时,网站也需要严 ...

最新文章

  1. JavaScript--正则
  2. 微软发布通用型AI框架Avatar Framework
  3. 探秘新一代音视频技术融合通信平台全接触
  4. 【Python】如何在Windows操作系统下安装Python和Networkx
  5. QNX6.5编译libcurl
  6. 【开卷故意】记录一次高并发下的死锁解决思考过程
  7. 小目标检测、图像分类、图像识别等开源数据集汇总
  8. 前端趋势榜:上周最实用和 yyds 的 10 大前端项目 - 211128
  9. 从@Transactional看事务的传播和隔离
  10. OpenCV计算图像的平均值和标准差的函数meanStdDev函数的使用
  11. Spark没有读取HDFS文件的方法?那textFile是怎么读的?
  12. .NET6之MiniAPI(二十七):Metrics
  13. iphone 流媒体
  14. c++11 stl 学习之 shared_ptr
  15. mysql扩展中如何处理结果集_请写出PHP处理结果集的5个函数(使用mysql扩展)_学小易找答案...
  16. 如何才能更容易拿到大厂Offer?从理论到实践!
  17. html+css做的丝带标签
  18. [Flex] Flex 控件类 的自定义事件添加
  19. 用java实现mysql数据可视化_java可视化界面操作数据库编程.doc
  20. 由QQ魔法卡看腾讯的运作模式

热门文章

  1. 嵌入式Linux关闭串口打印-屏蔽串口打印
  2. python解析xml文件选用模块_python语言解析xml文件的常用的有两种方式
  3. java关闭io流_为什么要关闭和io流
  4. JOS学习笔记(三)
  5. Puppeteer - some case - 未完
  6. **打工人打工魂,争取外贸人上人**
  7. 计算两个并联电阻的总电阻
  8. 【加密解密】对exe文件的加密解密 含源代码》
  9. 推广引流方法有哪些?
  10. linux怎么进mysql天气_在Linux 命令行下浏览天气预报