最近在客户现场遇到一个棘手的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. Winform下编译Dev控件时提示license.licx文件错误

    有时候,用vs2005或2008,用到第3方控件的时候会自动生成licenses.licx.我用的是devexpress.在程序运行的时候总是出现dev的画面,很烦.在网上找了找,找到去掉画面的方法: ...

  2. springboot学习笔记:12.解决springboot打成可执行jar在linux上启动慢的问题

    有时候,当你把你的springboot项目打成可执行的jar,放在linux上启动时,发现启动超级慢: 这往往是因为springboot内置tomcat启动时实例化SecureRandom对象随机数策 ...

  3. Leetcode13_罗马数字转整数

    题目 罗马数字包含以下七种字符: I, V, X, L,C,D 和 M. 字符 数值I 1V 5X 10L 50C 100D 500M 1000例如, 罗马数字 2 写做 II ,即为两个并列的 1. ...

  4. ccpc20190823

    04 http://acm.hdu.edu.cn/showproblem.php?pid=6705 分析:先把每条边以 形式放进堆,堆按路径权值从小到大排序,然后每次取出堆顶,用v的出边扩展 新的路径 ...

  5. Emgu.CV.CvInvoke的类型初始值设定项引发异常”TypeInitializationException”的问题

    问题如图: 解决方案: 1.记住EmguCV的安装位置:X:\XXX\XXX… 本测试方案中EmguCV的安装位置:D:\Emgu,操作时记得用自己的EmguCV安装路径替换掉D:\Emgu. 2.添 ...

  6. python-django框架-电商项目-商品模块开发_20191124

    用户浏览记录的添加 什么时候添加历史浏览记录? 在商品详情的视图里面添加浏览记录, 之前使用的list来存储浏览记录, 注意:如果good_id之前已经浏览过了,那就要移除,conn.lrem(his ...

  7. Redis学习之热点key重建

    在Redis的生产环境中,大量客户端连接请求某一个key,但都需要从DB中获取数据,来回写数据库,如下图: <ignore_js_op> 造成的问题: 大量的线程请求数据库,造成数据库压力 ...

  8. Nunit说明及简单DEMO

    using System; using System.Collections.Generic; using System.Text; using NUnit.Framework; //安装好NUnit ...

  9. Android开发之《ffmpeg解码mjpeg视频流》

    MJPEG格式和码流分析,MJPEG格式的一些简介 FFmpeg解码USB摄像头MJPEG输出:http://blog.csdn.net/light_in_dark/article/details/5 ...

  10. python的IO

    格式化输出 格式化输出是指通过print()等函数向指定的地方(比如屏幕)输出指定格式的内容 格式: age = 18 name = "xiaohua" print("我 ...