使用HttpsURLConnection访问HTTPS连接时通常须要引入证书,不然会产生异常。
可是也可使用信任全部证书的方式来达到访问的目的。
经上网查询资料发现一个很好用的类来实现信任全部证书的功能。特此记录。
代码来自[这里](http://javaweb.org/?p=1237)
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class SslUtils {
private static void trustAllHttpsCertificates() throws Exception {
TrustManager[] trustAllCerts = new TrustManager[1];
TrustManager tm = new miTM();
trustAllCerts[0] = tm;
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
}
static class miTM implements TrustManager, X509TrustManager {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public boolean isServerTrusted(X509Certificate[] certs) {
return true;
}
public boolean isClientTrusted(X509Certificate[] certs) {
return true;
}
public void checkServerTrusted(X509Certificate[] certs, String authType)
throws CertificateException {
return;
}
public void checkClientTrusted(X509Certificate[] certs, String authType)
throws CertificateException {
return;
}
}
/**
* 忽略HTTPS请求的SSL证书,必须在openConnection以前调用
*
* @throws Exception
*/
public static void ignoreSsl() throws Exception {
HostnameVerifier hv = new HostnameVerifier() {
public boolean verify(String urlHostName, SSLSession session) {
System.out.println("Warning: URL Host: " + urlHostName + " vs. " + session.getPeerHost());
return true;
}
};
trustAllHttpsCertificates();
HttpsURLConnection.setDefaultHostnameVerifier(hv);
}
}
在openConnection以前调用SslUtils.ignoreSsl();便可忽略全部HTTPS连接的证书。
在web应用交互过程当中,有不少场景须要保证通讯数据的安全;在前面也有好多篇文章介绍了在Web Service调用过程当中用WS-Security来保证接口交互过程的安全性,值得注意的是,该种方式基于的传输协议仍然是Http,采用这种方式可扩展性和数据交互效率比较高;另一种实现方式就是用Https,他是在协议层对Http的再次封装,加入了SSL/TLS,采用该协议进行通讯的数据所有都会被加密,因为目前Web开发编程中对此都有了必定程度的封装,因此采用Https对外提供服务,除了证书之外,对编程能力的要求并不高,相对于前者门槛较低,可是因为对双方通讯的全部数据都进行加密,并且交互过程当中还有屡次握手等,因此效率较低;如下就介绍下在Java中访问Https连接时会出现的一些问题;html
在Java中要访问Https连接时,会用到一个关键类HttpsURLConnection;参见以下实现代码:java
在取得connection的时候和正常浏览器访问同样,仍然会验证服务端的证书是否被信任(权威机构发行或者被权威机构签名);若是服务端证书不被信任,则默认的实现就会有问题,通常来讲,用SunJSSE会抛以下异常信息:
javax.NET.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested targetweb
上面提到SunJSSE,JSSE(Java Secure Socket Extension)是实现Internet安全通讯的一系列包的集合。它是一个SSL和TLS的纯Java实现,能够透明地提供数据加密、服务器认证、信息完整性等功能,可使咱们像使用普通的套接字同样使用JSSE创建的安全套接字。JSSE是一个开放的标准,不仅是Sun公司才能实现一个SunJSSE,事实上其余公司有本身实现的JSSE,而后经过JCA就能够在JVM中使用。
关于JSSE的详细信息参考官网Reference:http://java.sun.com/j2se/1.5.0/docs/guide/security/jsse/JSSERefGuide.html;
以及java Security Guide:http://java.sun.com/j2se/1.5.0/docs/guide/security/;编程
在深刻了解JSSE以前,须要了解一个有关Java安全的概念:客户端的TrustStore文件。客户端的TrustStore文件中保存着被客户端所信任的服务器的证书信息。客户端在进行SSL链接时,JSSE将根据这个文件中的证书决定是否信任服务器端的证书。在SunJSSE中,有一个信任管理器类负责决定是否信任远端的证书,这个类有以下的处理规则:
一、若系统属性javax.net.sll.trustStore指定了TrustStore文件,那么信任管理器就去jre安装路径下的lib/security/目录中寻找并使用这个文件来检查证书。
二、若该系统属性没有指定TrustStore文件,它就会去jre安装路径下寻找默认的TrustStore文件,这个文件的相对路径为:lib/security/jssecacerts。
三、若jssecacerts不存在,可是cacerts存在(它随J2SDK一块儿发行,含有数量有限的可信任的基本证书),那么这个默认的TrustStore文件就是lib/security/cacerts。浏览器
那遇到这种状况,怎么处理呢?有如下两种方案:
一、按照以上信任管理器的规则,将服务端的公钥导入到jssecacerts,或者是在系统属性中设置要加载的trustStore文件的路径;证书导入能够用以下命令:keytool -import -file src_cer_file –keystore dest_cer_store;至于证书能够经过浏览器导出得到;
二、实现本身的证书信任管理器类,好比MyX509TrustManager,该类必须实现X509TrustManager接口中的三个method;而后在HttpsURLConnection中加载自定义的类,能够参见以下两个代码片断,其一为自定义证书信任管理器,其二为connect时的代码:安全
对于以上两种实现方式,各有各的优势,第一种方式不会破坏JSSE的安全性,可是要手工导入证书,若是服务器不少,那每台服务器的JRE都必须作相同的操做;第二种方式灵活性更高,可是要当心实现,不然可能会留下安全隐患;服务器