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

1 篇文章 0 订阅
1 篇文章 0 订阅

此篇只涉及到如果访问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

方式一: 使用 HttpURLConnection

给 HttpURLConnection 类设置默认的 SSL

导入的包, 都是 JDK 内置的的

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 协议的链接了.

方式二: 使用 HttpsURLConnection

HttpsURLConnection 是对 HttpURLConnection 的扩展, 支持各种特定于 https 功能 .

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

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

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

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

URL url = new URL(path);
// 强转为 HttpsURLConnection , 设置 SSLSocketFactory
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setSSLSocketFactory(ssf);

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

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

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

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

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

/**
 * 该方法检查客户端的证书,若不信任该证书则抛出异常。
 *
 * 由于我们不需要对客户端进行认证,因此我们只需要执行默认的信任管理器的这个方法。
 * JSSE中,默认的信任管理器类为 TrustManager。
 * 
 */
void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException
/**
 * 该方法检查服务器的证书,若不信任该证书同样抛出异常。
 *
 * 通过自己实现该方法,可以使之信任我们指定的任何证书。在实现该方法时,也可以简单的不做任何处理,即
 * 一个空的函数体,由于不会抛出异常,它就会信任任何证书。
 */
void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException
/**
 * 返回受信任的X509证书数组。
 */
X509Certificate[] getAcceptedIssuers()

自己实现了信任管理器类,如何使用呢?HttpsURLConnection 类似乎并没有提供方法设置信任管理器。

其实,HttpsURLConnection 通过 SSLSocket 来建立与 HTTPS 的安全连接,SSLSocket 对象是由 SSLSocketFactory 生成的。HttpsURLConnection 提供了方法 setSSLSocketFactory(SSLSocketFactory) 设置它使用的 SSLSocketFactory 对象。SSLSocketFactory 通过 SSLContext 对象来获得,在初始化 SSLContext 对象时,可指定信任管理器对象。

假设自己实现的 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的安全性,但需要手工导入证书;第二种方法虽然不用手工导入证书,但需要小心使用,否则会带来一些安全隐患。

  • 10
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
要利用Java的HttpURLConnection类实现HTTPS请求,可以通过以下步骤实现: 1. 创建一个URL对象,指向要请求HTTPS地址。 2. 调用URL对象的openConnection()方法,获取URLConnection对象。 3. 将URLConnection对象转换为HttpsURLConnection对象。 4. 设置HttpsURLConnection对象的一些连接属性,例如SSLContext、HostnameVerifier等。 5. 发送请求并获取响应。 下面是一个示例代码: ```java import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; public class HttpsClient { public static void main(String[] args) throws Exception { String httpsURL = "https://example.com"; URL myUrl = new URL(httpsURL); HttpURLConnection conn = (HttpURLConnection)myUrl.openConnection(); if (conn instanceof HttpsURLConnection) { HttpsURLConnection httpsConn = (HttpsURLConnection)conn; SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, new TrustManager[] { new X509TrustManager() { public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {} public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) {} public java.security.cert.X509Certificate[] getAcceptedIssuers() { return new java.security.cert.X509Certificate[]{}; } } }, new java.security.SecureRandom()); httpsConn.setSSLSocketFactory(sslContext.getSocketFactory()); httpsConn.setHostnameVerifier((hostname, session) -> true); } BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream())); String input; while ((input = br.readLine()) != null) { System.out.println(input); } br.close(); } } ``` 在这个示例中,我们首先创建了一个URL对象,然后使用openConnection()方法获取URLConnection对象。由于我们要访问的是HTTPS地址,因此我们需要将URLConnection对象转换为HttpsURLConnection对象,并设置SSLContext和HostnameVerifier。最后,我们发送请求并读取响应。需要注意的是,由于我们使用了自定义的TrustManager和HostnameVerifier,因此它不会验证证书,因此在实际生产环境中需要谨慎使用

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值