脚本宝典收集整理的这篇文章主要介绍了

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

关于java访问https资源时,忽略证书信任问题-脚本宝典
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);

以下是一个具体的例子:

import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL;  import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLSession;  import org.apache.log4j.Logger; import org.htmlparser.util.ParserException;  import com.xwtech.parser.GetRequestHtmlParser; import com.xwtech.pojo.ExtendCandidate; /*  * GET请求类  */ public class GetRequest {     private String url = "https://b2b.10086.cn/b2b/main/viewNoticeContent.html?noticeBean.id=";     private Logger logger;     public GetRequest() {         logger = Logger.getLogger(GetRequest.class);     }     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());     }     public void getData(String id) {         this.url = url + id;         BufferedReader in = null;         HttpURLConnection conn = null;         String result = "";         try {         //该部分必须在获取connection前调用             trustAllHttpsCertificates();             HostnameVerifier hv = new HostnameVerifier() {                 public boolean verify(String urlHostName, SSLSession session) {                     logger.info("Warning: URL Host: " + urlHostName + " vs. " + session.getPeerHost());                     return true;                 }             };             HttpsURLConnection.setDefaultHostnameVerifier(hv);             conn = (HttpURLConnection)new URL(url).openConnection();             // 发送GET请求必须设置如下两行             conn.setDoInput(true);             conn.setRequestMethod("GET");             // flush输出流的缓冲             in = new BufferedReader(new InputStreamReader(conn.getInputStream()));             String line;             while ((line = in.readLine()) != null) {                 result += line;             }         } catch (Exception e) {             logger.error("发送 GET 请求出现异常!t请求ID:"+id+"n"+e.getMessage()+"n");         } finally {// 使用finally块来关闭输出流、输入流             try {                 if (in != null) {                     in.close();                 }             } catch (IOException ex) {                 logger.error("关闭数据流出错了!n"+ex.getMessage()+"n");             }         }         // 获得相应结果result,可以直接处理......              }     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;         }     } }

总结

以上是脚本宝典为你收集整理的

关于java访问https资源时,忽略证书信任问题

全部内容,希望文章能够帮你解决

关于java访问https资源时,忽略证书信任问题

所遇到的程序开发问题,欢迎加入QQ群277859234一起讨论学习。如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典网站推荐给程序员好友。 本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。

80%的人都看过