无根证书时访问 https

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
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.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

/**
 * 通过自定义 TrustManager 来实现无根证书时访问 https
 * @date    2013-8-29
 * @file    HttpsClient.java
 */
public class HttpsClient {
    
	/**
	 * 测试 https
	 * @param args
	 */
	public static void main(String[] args) throws Exception {
		// init https
		HttpsClient.init();
		
		URL url = new URL("https://www.12306.cn/mormhweb/");
		url.openConnection();
		InputStream in = url.openStream();
		BufferedReader buf = new BufferedReader(new InputStreamReader(in));
		String line = null;
		while ((line = buf.readLine()) != null){
			System.out.println(line);
		}
		buf.close();
		in.close();
		
		System.out.println("-- finished --");
	}
    
	/**
	 * 初始化
	 */
	public static void init() {
		try {
			SSLContext sslCtx = SSLContext.getInstance("TLS");
			sslCtx.init(null, new TrustManager[]{new MyTrustManager()}, null);
			SSLSocketFactory sslSocketFactory = sslCtx.getSocketFactory();
			HttpsURLConnection.setDefaultSSLSocketFactory(sslSocketFactory);
			HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
				@Override
				public boolean verify(String hostname, SSLSession session) {
					return true;
				}
			});
		}
		catch (Exception e) {
			e.printStackTrace();
		}
	}
}
/**
 * 默认信任服务端根证书
 */
class MyTrustManager implements X509TrustManager {
    
	@Override
	public void checkClientTrusted(X509Certificate[] chain, String authType)
			throws CertificateException {
		return;
	}
    
	@Override
	public void checkServerTrusted(X509Certificate[] chain, String authType)
			throws CertificateException {
		return;
	}
    
	@Override
	public X509Certificate[] getAcceptedIssuers() {
		return null;
	}
}
# 访问 https 时有两个问题需要注意
# 1. 客户端需要存在有效的根证书
相应的异常信息:
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:196)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:268)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:380)
... 19 more
处理方法:
HttpsURLConnection.setDefaultSSLSocketFactory(sslSocketFactory);
# 2. 访问 https 时的域名需要与根证书中声明的域名一致
相应的异常信息:
Caused by: java.security.cert.CertificateException: No name matching www.12306.cn found
at sun.security.util.HostnameChecker.matchDNS(HostnameChecker.java:208)
at sun.security.util.HostnameChecker.match(HostnameChecker.java:93)
at sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:347)
at sun.security.ssl.AbstractTrustManagerWrapper.checkAdditionalTrust(SSLContextImpl.java:847)
at sun.security.ssl.AbstractTrustManagerWrapper.checkServerTrusted(SSLContextImpl.java:814)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1320)
... 13 more
处理方法:
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
	@Override
	public boolean verify(String hostname, SSLSession session) {
		return true;
	}
});
# 相关链接
http://wenku.baidu.com/view/ce0f191852d380eb62946d6a.html
http://blog.csdn.net/faye0412/article/details/6883879

你可能感兴趣的:(https)