使用HttpURLConnection访问https协议请求时.对SSL信任

此篇只涉及到如果访问https链接, 具体的原理不做深究.    

当我们使用HttpURLConnection访问http请求的时候没有任何困难, 但是当访问https协议的链接时, 由于证书的问题, 就涉及到此链接的证书验证. 可以保证安全的通信, 但是对爬虫来说, 会变得非常的麻烦. 所以我们需要对https协议的链接在代码层实现信任此链接. 

    第一步: 实现X509TrustManager接口

package util;

import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.X509TrustManager;

public class MyX509TrustManager implements X509TrustManager{

	@Override
	public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
		// TODO Auto-generated method stub
		
	}

	@Override
	public X509Certificate[] getAcceptedIssuers() {
		// TODO Auto-generated method stub
		return null;
	}

}

这一步非常简单, 不需要实现任何方法, 也就是没有做任何的验证, 相当于所有的https链接都设为信任.

第二步: 请求类, 可以使用HttpURLConnection或者HttpsURLConnection

(1)给HttpURLConnection类设置默认的SSL

导入的包, 都是自带的

import java.net.URL;
import java.security.SecureRandom;
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;
SSLContext sslcontext = SSLContext.getInstance("SSL", "SunJSSE");//第一个参数为协议,第二个参数为提供者(可以缺省)
TrustManager[] tm = {new MyX509TrustManager()};
sslcontext.init(null, tm, new SecureRandom());
HostnameVerifier ignoreHostnameVerifier = new HostnameVerifier() {
	public boolean verify(String s, SSLSession sslsession) {
		System.out.println("WARNING: Hostname is not matched for cert.");
			return true;
	}
};
HttpsURLConnection.setDefaultHostnameVerifier(ignoreHostnameVerifier);
HttpsURLConnection.setDefaultSSLSocketFactory(sslcontext.getSocketFactory());
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();

然后就可以用conn去访问https协议的链接了.

(2)对一个HttpsURLConnection是对HttpURLConnection的扩展, 支持各种特定于 https 功能 . 

这里我们用到了其中设计SSL的方法

 
 
public SSLSocketFactory getSSLSocketFactory()
获取为安全 https URL 连接创建套接字时使用的 SSL 套接字工厂。 
返回:
SSLSocketFactory

具体的代码和设置默认的SSL比较类似, 导入的包不变:

SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");//第一个参数为 返回实现指定安全套接字协议的SSLContext对象。第二个为提供者
TrustManager[] tm = {new MyX509TrustManager()};
sslContext.init(null, tm, new SecureRandom());
SSLSocketFactory ssf = sslContext.getSocketFactory();  

URL url = new URL(path);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setSSLSocketFactory(ssf);

然后就可以用此conn来访问https协议的链接了.


网上看到的关于证书详解, 没有找到原出处, 对原作者抱歉

X509证书信任管理器类的详解 


在JSSE中,证书信任管理器类就是实现了接口X509TrustManager的类。我们可以自己实现该接口,让它信任我们指定的证书。

接口X509TrustManager有下述三个公有的方法需要我们实现:


        ⑴ oid checkClientTrusted(X509Certificate[] chain, String authType) 

throws CertificateException

  该方法检查客户端的证书,若不信任该证书则抛出异常。由于我们不需要对客户端进行认证,因此我们只需要执行默认的信任管理器的这个方法。JSSE中,默认的信任管理器类为TrustManager。


  ⑵ oid checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException
  该方法检查服务器的证书,若不信任该证书同样抛出异常。通过自己实现该方法,可以使之信任我们指定的任何证书。在实现该方法时,也可以简单的不做任何处理,即一个空的函数体,由于不会抛出异常,它就会信任任何证书。


  ⑶ X509Certificate[] getAcceptedIssuers()
返回受信任的X509证书数组。


  自己实现了信任管理器类,如何使用呢?类HttpsURLConnection似乎并没有提供方法设置信任管理器。其实,HttpsURLConnection通过SSLSocket来建立与HTTPS的安全连接,SSLSocket对象是由SSLSocketFactory生成的。HttpsURLConnection提供了方法setSSLSocketFactory(SSLSocketFactory)设置它使用的SSLSocketFactory对象。SSLSocketFactory通过SSLContext对象来获得,在初始化SSLContext对象时,可指定信任管理器对象。下面用一个图简单表示这几个JSSE类的关系:

                图1 部分JSSE类的关系图


  假设自己实现的X509TrustManager类的类名为:MyX509TrustManager,下面的代码片断说明了如何使用MyX509TrustManager:


//创建SSLContext对象,并使用我们指定的信任管理器初始化
TrustManager[] tm = {new MyX509TrustManager ()};
SSLContext sslContext = SSLContext.getInstance("SSL","SunJSSE");
sslContext.init(null, tm, new java.security.SecureRandom());
//从上述SSLContext对象中得到SSLSocketFactory对象
SSLSocketFactory ssf = sslContext.getSocketFactory();
//创建HttpsURLConnection对象,并设置其SSLSocketFactory对象
HttpsURLConnection httpsConn = (HttpsURLConnection)myURL.openConnection();
httpsConn.setSSLSocketFactory(ssf);
  这样,HttpsURLConnection对象就可以正常连接HTTPS了,无论其证书是否经权威机构的验证,只要实现了接口X509TrustManager的类MyX509TrustManager信任该证书。

    小结


   本文主要介绍了在HTTPS的证书未经权威机构认证的情况下,访问HTTPS站点的两种方法,一种方法是把该证书导入到Java的TrustStore文件中,另一种是自己实现并覆盖JSSE缺省的证书信任管理器类。两种方法各有优缺点,第一种方法不会影响JSSE的安全性,但需要手工导入证书;第二种方法虽然不用手工导入证书,但需要小心使用,否则会带来一些安全隐患。

猜你喜欢

转载自blog.csdn.net/zz153417230/article/details/80271155