背景
话不多说,直接上堆栈
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.ssl.Alerts.getSSLException(Alerts.java:192) at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949) at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302) at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296) at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1514) at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216) at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1026) at sun.security.ssl.Handshaker.process_record(Handshaker.java:961) at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062) at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375) at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403) at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387) at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:436) at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:384) at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:142) at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:376) at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:393) at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236) at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:186) at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89) at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110) at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108) Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:387) at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292) at sun.security.validator.Validator.validate(Validator.java:260) at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324) at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229) at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124) at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1496) ... 51 more Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141) at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126) at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280) at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382) ... 57 more
上面是某客户环境出现的错误,从错误信息中大概猜测是https证书出了问题,据开发反馈这个接口使用了近半年,一直没有问题,我随即跟运维打探情况,看近期是否有什么调整。
果然,由于客户的证书即将到期,所以申请了新证书,昨天晚上刚更新到nginx上去,但是更新完以后客户、实施都在浏览器测试了,并没有问题,怎么程序里HttpClient访问就报错了呢?
带着疑问我又测试了curl命令和postman工具,接连失败,如下图所示:
发现新大陆
机缘巧合下我发现了一个好用的ssl工具网站myssl.com,目前解锁了两个很实用的工具,在这里推荐给大家:
1.网站检测工具,直接输入域名然后“立即检测”
如果证书链不完整就会有明确的提示和操作办法,接着介绍下一个好用的工具。
2.证书补全工具https://myssl.com/chain_download.html,只要输入域名或者上传证书文件就可以自动补全证书链,非常好用。
了解了上面的两个ssl工具以后我们这个问题迎刃而解,借助工具补齐证书链然后替换nginx上有问题的证书文件即可。
https证书链的作用
本节内容来源于沃通官网的扫盲内容,有兴趣的前往推荐阅读第二条
当我们把SSL证书申请下来时通常会有三个文件,包括证书的私钥文件、证书的公钥文件和一个证书链文件,貌似我们把私钥文件和公钥文件部署到服务器上就可以了,浏览器也正常识别SSL证书,那证书链文件还有什么用,可以不用吗,本文就解释一下证书链文件以及它起到的作用。
SSL证书的构成
一般我们下载的证书有私钥文件、公钥文件和一个证书链文件,如下图
云服务器申请的证书public文件就是公钥打开也就是我们的网站证书,chain文件就是证书链文件,key文件是私钥,第一个文件是公钥和证书链文件合成的文件。下面是从let's encrypt申请的证书,里面的key文件是私钥,certificate文件是我的网站的证书其内容就是公钥,ca_bundle就是证书链文件打开可以看到CA中间证书。
证书的结构如上图所示,一般是由CA根证书机构--CA中间证书机构--我们的网站证书构成,中间证书还可能存在多层关系。
浏览器验证SSL证书
系统或浏览器中预置了一些受信任的根证书颁发机构和某些中间证书颁发机构,ssl证书在被验证时最终要验证其根证书是否可信,网站证书的根证书在浏览器可信任根证书列表里才会被信任或者中间证书颁发机构可信其证书也是可信的,否则浏览器则会报告网站的证书来自未知授权中心。可是证书一般是由三级或多级结构构成,浏览器是不能通过用户证书直接验证其根证书的,这时中间证书即证书链文件起了作用,证书链文件告诉了浏览器用户证书的上级证书机构即中间证书,浏览器再通过中间证书验证其上级根证书是否为可信。
在用户证书里面我们会找到这样的信息,Authority Info Access(权威信息访问),通过这里面的 URL ,我们可以获得这个证书的颁发者证书,即中间证书。就是说我们在部署SSL证书时没有把证书链文件(中间证书)部署进去,浏览器依然可以通过证书上面的url信息访问到中间证书,继而验证根证书。
其他工具访问有问题,偏偏浏览器正常
本来问题解决完就完事了,但技术人员那颗心哪,就是凡事都要个结果,要不晚上又睡不踏实了。
如果您的业务用户通过浏览器访问您的Web业务,则您无需关注根证书和中间证书,因为根证书和中间证书已经内置在浏览器。您只需在Web服务器安装经CA签发的SSL证书,即可实现客户端与服务端的HTTPS通信。
如果业务用户通过Java等客户端访问您的Web业务,由于客户端没有内置根证书和中间证书,您可能需要在对应客户端手动安装根证书和中间证书,保证客户端能够校验服务端的加密信息。
这是我从阿里云网站上找到的答案,更多详细信息可以前往推荐阅读第三条。
标签: # https
留言评论