zoukankan      html  css  js  c++  java
  • java在访问https资源时,忽略证书信任问题 (转)

    java程序在访问https资源时,出现报错
    sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    这本质上,是java在访问https资源时的证书信任问题。如何解决这个问题呢?

    为何有这个问题?
    解决这个问题前,要了解
    1)https通信过程

    1. 客户端在使用HTTPS方式与Web服务器通信时有以下几个步骤,如图所示。
    2. 客户使用https的URL访问Web服务器,要求与Web服务器建立SSL连接。
    3. Web服务器收到客户端请求后,会将网站的证书信息(证书中包含公钥)传送一份给客户端。
    4. 客户端的浏览器与Web服务器开始协商SSL连接的安全等级,也就是信息加密的等级。
    5. 客户端的浏览器根据双方同意的安全等级,建立会话密钥,然后利用网站的公钥将会话密钥加密,并传送给网站。
    6. Web服务器利用自己的私钥解密出会话密钥。
    7. Web服务器利用会话密钥加密与客户端之间的通信。

    2)java程序的证书信任规则
    如上文所述,客户端会从服务端拿到证书信息。调用端(客户端)会有一个证书信任列表,拿到证书信息后,会判断该证书是否可信任。
    如果是用浏览器访问https资源,发现证书不可信任,一般会弹框告诉用户,对方的证书不可信任,是否继续之类。
    Java虚拟机并不直接使用操作系统的keyring,而是有自己的security manager。与操作系统类似,jdk的security manager默认有一堆的根证书信任。如果你的https站点证书是花钱申请的,被这些根证书所信任,那使用java来访问此https站点会非常方便。因此,如果用java访问https资源,发现证书不可信任,则会报文章开头说到的错误。
    解决问题的方法

    1. 将证书导入到jdk的信任证书中(理论上应该可行,未验证)
    2. 在客户端(调用端)添加逻辑,忽略证书信任问题

    第一种方法,需要在每台运行该java程序的机器上,都做导入操作,不方便部署,因此,采用第二种方法。下面贴下该方法对应的代码。

    验证可行的代码
    1)先实现验证方法

    HostnameVerifier hv = new HostnameVerifier() {
            public boolean verify(String urlHostName, SSLSession session) {
                System.out.println("Warning: URL Host: " + urlHostName + " vs. "
                                   + session.getPeerHost());
                return true;
            }
        };
     
     private static void trustAllHttpsCertificates() throws Exception {
     javax.net.ssl.TrustManager[] trustAllCerts = new javax.net.ssl.TrustManager[1];
     javax.net.ssl.TrustManager tm = new miTM();
     trustAllCerts[0] = tm;
     javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext
     .getInstance("SSL");
     sc.init(null, trustAllCerts, null);
     javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc
     .getSocketFactory());
     }
     
     static class miTM implements javax.net.ssl.TrustManager,
     javax.net.ssl.X509TrustManager {
     public java.security.cert.X509Certificate[] getAcceptedIssuers() {
     return null;
     }
     
     public boolean isServerTrusted(
     java.security.cert.X509Certificate[] certs) {
     return true;
     }
     
     public boolean isClientTrusted(
     java.security.cert.X509Certificate[] certs) {
     return true;
     }
     
     public void checkServerTrusted(
     java.security.cert.X509Certificate[] certs, String authType)
     throws java.security.cert.CertificateException {
     return;
     }
     
     public void checkClientTrusted(
     java.security.cert.X509Certificate[] certs, String authType)
     throws java.security.cert.CertificateException {
     return;
     }
     }
    2)在访问https资源前,调用
     
    trustAllHttpsCertificates();
    HttpsURLConnection.setDefaultHostnameVerifier(hv);

    参考文档(本文其实是将这三篇文章中,相关的内容整合到一起):
    http://blog.csdn.net/mingli198611/article/details/8055261《HTTP和HTTPS详解》
    http://www.cnblogs.com/wupher/archive/2012/08/05/2623561.html《使用Keytool为JDK添加https证书信任》
    http://mengyang.iteye.com/blog/575671《解决PKIX path building failed的问题》
    原文链接:https://blog.csdn.net/lizeyang/article/details/18983843

  • 相关阅读:
    ofbiz初级教程
    IBASE4J开发环境搭建
    Nginx在windows上安装 及 Nginx的配置及优化
    Windows里正确安装Zookeeper以服务运行
    分享一个完整的Mybatis分页解决方案
    jquery weui ajax滚动加载更多
    Spring+Mybatis+SpringMVC后台与前台分页展示实例
    Mysql怎么样避免全表扫描,sql查询优化
    SQL优化|Java面试题
    mysql 全表扫描、全索引扫描、索引覆盖(覆盖索引)
  • 原文地址:https://www.cnblogs.com/guanbin-529/p/11642148.html
Copyright © 2011-2022 走看看