解析Java为什么不接受合法的HTTPS证书

欢迎访问PlayScala社区,转载请注明沐风(joymufeng)

在我们使用Java调用远程接口或是抓取数据时经常会发生以下错误:

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:281)
    at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:136)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1496)
    ... 27 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)
    ... 33 more

这个错误表明Java虚拟机在请求远程HTTPS服务器时无法验证证书的有效性,由于担心HTTPS中间人劫持,所以抛出错误警告调用者。可是奇怪的是这个HTTPS链接在浏览器中可以被正确访问,这是为什么呢?别急,听我慢慢道来。

什么是HTTPS/SSL证书?

HTTPS/SSL证书是由权威CA(Certificate Authority)机构颁发,主要用于服务器(应用)数据传输链路加密和身份认证,以及绑定网站域名。主要有EV SSL证书(Extended Validation SSL),OV SSL证书(Organization Validation SSL)和DV SSL证书(Domain Validation SSL)等。不同的证书类型在浏览器标识上会享受不同的待遇,例如EV、OV证书在浏览器地址栏上会显示企业名称,当然也意味着你在向CA机构申请证书时要付更多的钱,走更多的审核流程。通常DV证书就足够用了,审核流程简单,并且很便宜。
我们上面说到HTTPS/SSL证书是由CA机构颁发的,为了方便运营,CA机构下面还有很多的代理商,这些代理商就是所谓的中间证书颁发机构(Intermediate Certificate Authority),一些大的代理商下面还会继续设置代理商。通常我们的证书都是在代理商或者叫中间证书颁发机构那里申请的。

如何验证证书的有效性?

HTTPS/SSL证书是一种非对称加密技术,HTTPS/SSL证书中包含了所有者的一些基本信息和对外公开的公钥,也就是说HTTPS/SSL证书其实就是所有者的一张名片,但是谁能证明这张名片上的信息是否属实呢? 就像是你拿着一个破手镯,到马路上然后逢人就说"我是马云私生子,看,这是他留给我的手镯,上面还有他的签名。",显然不会有人相信你。但是如果马云站出来,一把抢过手镯仔细端详一番后,抱着你痛哭流涕,那么这个手镯确实可以证明你是马云私生子。HTTPS/SSL证书的作用就像这个手镯,需要经过权威机构认证,通过了认证才会得到大家的认可。所以你的证书需要经过你的代理商认证,代理商的证书需要经过父级代理商认证,... ,这样层层认证一直到顶层的CA机构。所以:

HTTPS/SSL证书其实是一个证书链,这条链上的所有证书均合法才能表明证书本身的合法性。

Java的HTTPS/SSL证书错误分析

搞清楚证书链概念后我们再回头看一下本文开头的错误,其实原因很简单。浏览器成功地完成了整条证书链的校验,所以认为证书是合法的;而在Java中未能完成整条证书链的校验,例如无法验证某个中间证书颁发机构的合法性,所以导致最终认证失败。例如域名chatbot.cn的证书链如下:


中间证书COMODO RSA Domain Validation Secure Server CA的指纹为:
‎33 9c dd 57 cf d5 b1 41 16 9b 61 5f f3 14 28 78 2d 1d a6 39

CA机构COMODO SECURE的指纹为:
af e5 d2 44 a8 d1 19 42 30 ff 47 9f e2 f8 97 bb cd 7a 8c b4

下面我们看下Windows证书管理器中收录的CA证书和中间证书,单击开始-运行,输入certmgr.msc回车,单击菜单栏【操作】-【查找证书】, 输入COMODO,分别搜索“中间证书颁发机构”和“受信任的根证书颁发机构”,结果如下:


该证书的指纹为:
33 9c dd 57 cf d5 b1 41 16 9b 61 5f f3 14 28 78 2d 1d a6 39


该证书指纹为:
‎af e5 d2 44 a8 d1 19 42 30 ff 47 9f e2 f8 97 bb cd 7a 8c b4

由于在Windows上整条证书链的认证是完整的,所以在浏览器中可以成功验证证书的有效性。
我们再来看一下Java这边,Java拥有自己的keystore(通常位于$JAVA_HOME/lib/security/cacerts)用于存储CA证书和中间证书,双击$JAVA_HOME/bin/javacpl.exe打开Java控制台,单击【安全】- 【管理证书】,选择【系统】选项卡,然后单击证书类型下拉框查看相关证书。其实还有一种更简单的办法查看Java的信任证书列表,执行如下命令:
keytool -keystore "$JAVA_HOME\jre\lib\security\cacerts" -storepass changeit -list

该命令输出结果如下:

C:\Users\Lenovo>keytool -keystore "D:\Software\jdk1.8.0_111\jre\lib\security\cacerts" -storepass changeit -list

密钥库类型: JKS
密钥库提供方: SUN

您的密钥库包含 104 个条目

digicertassuredidrootca, 2008-4-16, trustedCertEntry,
证书指纹 (SHA1): 05:63:B8:63:0D:62:D7:5A:BB:C8:AB:1E:4B:DF:B5:A8:99:B2:4D:43
comodorsaca, 2015-5-12, trustedCertEntry,
证书指纹 (SHA1): AF:E5:D2:44:A8:D1:19:42:30:FF:47:9F:E2:F8:97:BB:CD:7A:8C:B4
thawtepremiumserverca, 2015-5-21, trustedCertEntry,
...
...

在上面的输出中,我们只能找到CA机构COMODO SECURE的指纹(上面的倒数第4行),而找不到中间证书COMODO RSA Domain Validation Secure Server CA的指纹,所以在Java中无法验证整条证书链的有效性,所以导致Java程序在通过HTTPS协议访问chatbot.cn域名时发生证书错误。通常的解决办法是在Http Client端设置忽略证书错误,或是将缺少的中间证书导入Java keystore,详情请Google之。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容