• 解析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_HOMEjrelibsecuritycacerts" -storepass changeit -list

    该命令输出结果如下:

    C:UsersLenovo>keytool -keystore "D:Softwarejdk1.8.0_111jrelibsecuritycacerts" -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之。

    https://my.oschina.net/joymufeng/home
  • 相关阅读:
    数据结构选讲深入理解红黑树(Red Black Tree)
    [CLRS][CH 15.2] 动态规划之矩阵链乘法
    数据结构选讲树的旋转(Rotation)
    数据结构选讲二叉查找树(Binary Search Tree)
    [SICP][CH 2.2] 层次性数据和闭包性质
    [CLRS][CH 15.3] 动态规划基础
    数据结构选讲234树(234 Tree)
    IEnumerable与IEnumerator
    你日常所做的事情,决定你将永远成为什么样的人
    c#中正则表达中特殊字符的转义!
  • 原文地址:https://www.cnblogs.com/joymufeng/p/7493037.html
Copyright © 2020-2023  润新知