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

By | 02月08日
Advertisement

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);

参考文档(本文其实是将这三篇文章中,相关的内容整合到一起):

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的问题》

Similar Posts:

  • 使用java访问https链接时,不信任证书导致PKIX path building failed

    解决办法 使用keytool工具来设置jdk信任此站点. 1.下载该站点的证书文件,格式为Base64的cer文件. 2.cmd管理员身份运行,并进入到jre文件夹下. 注意:密钥库口令默认为changeit keytool -import -alias dahe -keystore cacerts -file dahe.cer 该口令会将站点的安全证书导入到信任库中,alias为别名(最好设置为该站点的名字),keystore是要导入到哪个文件中(java默认为jre/lib/security

  • 客户端访问https站点(自定义证书)--续

    续之前的博文–客户端访问https站点(自定义证书). 上述博文中,将客户端访问Https Server分为了三种方式: 浏览器方式 终端方式 java 程序 但除此之外,还有一种特殊的场景:Client端是一个用Glassfish部署的应用,在这种情况下不仅需要将Server的证书导入到JDK中,还需将该证书导入到Glassfish安装目录下的config/cacerts.jks文件中. 实际上,在Glassfish的启动参数里,有如下两个参数设置: -Djavax.net.ssl.keySt

  • 解决PKIX path building failed的问题,忽略证书信任问题

    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.

  • HttpClient 如何忽略证书验证访问https - ALLOW_ALL_HOSTNAME_VERIFIER (二)

    HttpClient 如何忽略证书验证访问https - ALLOW_ALL_HOSTNAME_VERIFIER(二) /** * @Title: getNewHttpClient * @Description: Methods Description * @param @return * @return HttpClient * @throws */ private HttpClient getNewHttpClient() { try { KeyStore trustStore = KeyS

  • Nginx配置SSL证书实现访问HTTPS网站

    本文转自服务器之家:Nginx配置SSL证书实现访问HTTPS网站 一.什么是 SSL 证书,什么是 HTTPS SSL 证书是一种数字证书,它使用 Secure Socket Layer 协议在浏览器和 Web服务器之间建立一条安全通道,从而实现: 1.数据信息在客户端和服务器之间的加密传输,保证双方传递信息的安全性,不可被第三方窃听: 2.用户可以通过服务器证书验证他所访问的网站是否真实可靠. HTTPS 是以安全为目标的 HTTP 通道,即 HTTP 下加入 SSL 加密层.HTTPS 不

  • [转]java 关于httpclient 请求https (如何绕过证书验证)

    原文:http://www.blogjava.net/hector/archive/2012/10/23/390073.html 第一种方法,适用于httpclient4.X 里边有get和post两种方法供你发送请求使用. 导入证书发送请求的在这里就不说了,网上到处都是 import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStream

  • Https请求忽略证书验证最新实现

    最近工作中需要和一个第三方公司进行https交互请求,但是对方的证书有一些问题,所以在发送请求的时候需要忽略证书验证.百度之后,发现已经有很多这方面的介绍,不过在使用其代码的时候总会有一些类不推荐使用了.下面是参考网上的常见方面并结合最新的官方API实现的一个最新方法(使用的主要jar包括httpclient-4.5.1.jar和httpcore-4.4.3.jar). public static List doPostByClient(String url, Map<?, ?> postDa

  • 从Java代码中访问 HTTPS 协议

    有个互联网上的网址:https://wtsz.jyzq.cn/ywcl.jsp?type=l&yybdm=1100&market=Z&userName=11009341&pwd=870221&ip=3.3.3.3&serverName=jyzq.cn,是HTTPS协议的,如何通过JAVA程序能够调用该地址得到正确的返回数据. 当前这个地址是可以通过浏览器访问的,需要在后台通过JAVA程序来访问. import java.io.IOException; imp

  • Java访问https网站出现hostname wrong

    java.io.IOException: HTTPS hostname wrong: should be <localhost> 异常处理 java.io.IOException: HTTPS hostname wrong: should be <localhost>: 原因:当访问HTTPS的网址.您可能已经安装了服务器证书到您的JRE的keystore .但这个错误是指服务器的名称与证书实际域名不相等.这通常发生在你使用的是非标准网上签发的证书. 解决方法:让JRE相信所有的证

  • 访问asp网站时,页面上显示请求的资源在使用中

    服务器生产环境: 操作系统:WIN2003 WEB:IIS 6.0 问题过程: 9月7日上午8:40左右,科研处长发现他们的网站无法登录,网上留言了我,当我进一步了解情况时,发现还有几个二级网站出现如下情况: 浏览器访问asp网站时,页面上显示请求的资源在使用中:有的ASP网站又可以正常访问,这就带来了一些困难,不知所措,到底发生了什么原因?如果在网上搜集一下,说一大堆原因,实际上一一测试,但无法解决. 此时此刻,心理非常紧张,又在抓紧时间进一步分析,如何解决此次网站运行故障. 通过以下设置,可

Tags: