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

2014-11-24 02:50:33 · 作者: · 浏览: 1
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服务器利用会话密钥加密与客户端之间的通信。 \
\

2)java程序的证书信任规则 如上文所述,客户端会从服务端拿到证书信息。调用端(客户端)会有一个证书信任列表,拿到证书信息后,会判断该证书是否可信任。 如果是用浏览器访问https资源,发现证书不可信任,一般会弹框告诉用户,对方的证书不可信任,是否继续之类。 Java虚拟机并不直接使用操作系统的keyring,而是有自己的security manager。与操作系统类似,jdk的security manager默认有一堆的根证书信任。如果你的https站点证书是花钱申请的,被这些根证书所信任,那使用java来访问此https站点会非常方便。因此,如果用java访问https资源,发现证书不可信任,则会报文章开头说到的错误。
解决问题的方法< http://www.2cto.com/kf/ware/vc/" target="_blank" class="keylink">vc3Ryb25nPgoxo6m9q9akyum1vMjrtb1qZGu1xNDFyM7WpMrp1tCjqMDtwtvJz9OmuMO/ydDQo6zOtNHp1qSjqQoyo6nU2r/Nu6e2y6OotffTw7bLo6nM7bzTwt+8raOsuvbC1NakyunQxcjOzsrM4gq12tK71ta3vbeoo6zQ6NKq1NrDv8yo1MvQ0LjDamF2YbPM0PK1xLv6xvfJz6OstrzX9rW8yOuy2df3o6yyu7e9seOyv8rwo6zS8rTLo6yyydPDtdq2/tbWt723qKGjz8LD5sz5z8K4w7e9t6i21NOmtcS0+sLroaMKPGJyPgoKPHN0cm9uZz48dT7R6dakv8nQ0LXEtPrC6zwvdT48L3N0cm9uZz4KMaOpz8jKtc/W0enWpLe9t6gKCjxwcmUgY2xhc3M9"brush:java;">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的问题》