最近在客户现场遇到一个棘手的http问题,现象很直接,访问某https的时候报错:

javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
at sun.security.ssl.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:)
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:)
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:)
at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:)
at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:)
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:)

从线程栈来看,是使用httpclient访问https服务的时候报错了,初步猜测是证书没有配置对,就想是不是要配置双向认证。

经过和现场工程师交流,发现这个只是个简单的单向认证,而且在浏览器使用GET发送请求,居然也是返回的200。

于是想到可能是JDK和程序本身的问题,根据httpclient写了个很简单的应用去访问,调用的错误环境下实际使用的JDK,发现也没有问题。

正要开始排查程序问题的时候,现场工程师说是另一个测试的https服务器通过应用程序可以访问通。这下立马有了头绪,可以抓个包对比一下https握手的过程。

果然,差别发现了:能够正常握手的https服务端返回了3个证书,握手错误的只返回了2个证书:

(正确的https服务器的通讯)

(有问题的https服务器的通讯)

看到这里,需要了解一个知识点了:信任库,只有信任库信任了密钥库的证书,才能进行通信。

我们详细看下密钥库的证书链:

发现多出来的证书是Baltimore CyberTrust Root

我们发现jdk能够信任这个多出来的和共有的证书

那为什么应用程序就不行呢,这个时候我们就需要使用jvm属性 -Djavax.net.debug=ssl:handshake了,他可以看到非常详细的https握手信息。

果然,输出的第一段日志就是trustStore is: /home/***/config/security/cacerts,原来使用的不是jdk的默认cacerts,而是自定义了-Djavax.net.ssl.trustStore的值。

那么问题就好解决了,删除即可。

再来看下这个配置的cacerts为啥不能认证,

原来他只信任了这个多出来的证书,机缘凑巧地能够访问测试的机器。验证了为什么能否访问一台https服务器,而另一台访问不了的问题。

另外日志中的一些其他信息我们也可以关注一下,便于遇到类似问题的时候分析:

1)关键字chain可以看到证书链的详细信息

2)两个非常有用的异常

handling exception: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building fail
ed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

IOException in getSession(): javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path bui

lding failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

参考:

1、HttpClient javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated when time shifted?

https://stackoverflow.com/questions/24752485/httpclient-javax-net-ssl-sslpeerunverifiedexception-peer-not-authenticated-when

2、Resolving javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed Error?

https://stackoverflow.com/questions/9619030/resolving-javax-net-ssl-sslhandshakeexception-sun-security-validator-validatore

3、javax.net.ssl.SSLHandshakeException的解决办法

https://blog.csdn.net/yiifaa/article/details/73148665

4、How to Analyze Java SSL Errors

https://dzone.com/articles/how-analyze-java-ssl-errors

https信任库采坑记的更多相关文章

  1. 分布式改造剧集之Redis缓存采坑记

    Redis缓存采坑记 ​ 前言 ​ 这个其实应该属于分布式改造剧集中的一集(第一集见前面博客:http://www.cnblogs.com/Kidezyq/p/8748961.html),本来按照顺序 ...

  2. Spring Cloud Config采坑记

    1. Spring Cloud Config采坑记 1.1. 问题 在本地运行没问题,本地客户端服务能连上本地服务端服务,可一旦上线,发现本地连不上线上的服务 服务端添加security登录加密,客户 ...

  3. k8s采坑记 - 解决二进制安装环境下证书过期问题

    前言 上一篇k8s采坑记 - 证书过期之kubeadm重新生成证书阐述了如何使用kubeadm解决k8s证书过期问题. 本篇阐述使用二进制安装的kubernetes环境,如何升级过期证书? k8s配置 ...

  4. Redis适配采坑记

    Redis适配采坑记 相对于其他的适配,Redis可以说是非常简单的其中只发现一个坑 问题一: 问题描述: redis认证失败 问题详解: redis连接配置时,本地需要采用password属性,远程 ...

  5. Service worker (@nuxtjs/workbox) 采坑记

    PWA(Progressive Web App)是前端的大趋势,它能极大的加快前端页面的加载速度,得到近乎原生 app 的展示效果(其实难说).PWA 其实是多种前端技术的组合,其中最重要的一个技术就 ...

  6. dubbo初学采坑记

    写在前面的话 dubbo 现在是apache组织旗下的项目,相信国内也有很多人使用.最近一个同事离职,我就接手了他的项目.远程通讯就是用的dubbo框架来实现的.使用Intelij idea 写了一个 ...

  7. tk.mybatis通用工具采坑记

    tk.mybatis通用工具pom <!--mybatis依赖--> <dependency> <groupId>org.mybatis.spring.boot&l ...

  8. 几行代码把Chrome搞崩溃之:HTML5 MP3录音由ScriptProcessorNode升级成AudioWorkletNode采坑记

    关键词: STATUS_ACCESS_VIOLATION AudioContext AudioWorkletNode audioWorklet addModule resume suspended c ...

  9. aidl使用采坑记

    什么是AIDL? AIDL是 Android Interface definition language的缩写,它是一种Android内部进程通信接口的描述语言,通过它我们可以定义进程间的通信接口 A ...

随机推荐

  1. java作业-----方法重载

    满足方法重载的条件:1.方法名相同    2.参数类型不同,参数个数不同,参数类型的顺序不同. 同时,方法的返回值不作为方法重载的判断条件.

  2. php中的几种四舍五入取整、向上取整、向下取整、小数截取方法

    echo intval(4.5);echo "<br />";//直接取整,舍弃小数保留整数echo round(4.5);echo "<br /> ...

  3. Python练习五-函数

    1.简述普通参数.指定参数.默认参数.动态参数的区别1)普通参数中,有形参和实参,其中形参是定义函数时写的参数,实参是调用函数时传给函数的参数:2)默认参数是在定义函数时,参数设定一个默认值:3)指定 ...

  4. easyui 表单提交前的 confirm 处理

    最近学习用 easyui,异步提交表单是遇到一个小问题 $('#fModiDetail').form('submit',{ url:'...', onSubmit:function(){ if($(t ...

  5. auth模块用法

    Auth模块: 如果你想用auth模块   那么你就用全套 createsuperuser  创建超级用户 这个超级用户就可以拥有登陆django admin后台管理的权限 Auth模块是Django ...

  6. iOS传感器集锦、飞机大战、开发调试工具、强制更新、Swift仿QQ空间头部等源码

    iOS精选源码 飞机大作战 MUPhotoPreview -简单易用的图片浏览器 LLDebugTool是一款针对开发者和测试者的调试工具,它可以帮... 多个UIScrollView.UITable ...

  7. LeetCode No.67,68,69

    No.67 AddBinary 二进制求和 题目 给定两个二进制字符串,返回他们的和(用二进制表示). 输入为非空字符串且只包含数字 1 和 0. 示例 输入: a = "11", ...

  8. python-django框架-电商项目-项目部署_20191127

    python-django框架-电商项目-项目部署: uwsgi作为web服务器: 在pycharm中启动项目:使用python manage.py runserver 这个runserver是dja ...

  9. rsync参数详解

    Rsync的参数详细解释 -v, --verbose 详细模式输出-q, --quiet 精简输出模式-c, --checksum 打开校验开关,强制对文件传输进行校验-a, --archive 归档 ...

  10. devexpress设置选中行

    版本2009.3 gvTagInfo.FocusedRowHandle = k; ;   //有效  gvTagInfo.FocusedRowHandle = k;              //这种 ...