HttpClient 4.5 利用HTTPS提交POST请求

最近在写一个测试服务器的程序,其中需要使用HTTPS协议,向服务器提交多个请求,由于服务器的证书是自己做的,因此要做证书的验证等工作。在网上查了许多例子,发现都不太合适,因为大部分代码都没做证书验证,所以容易受到中间人攻击。这里查阅了许多文档,并编写了自己的代码,做一个总结。

我这里使用了HttpClient 4.5版本。

参考了Oracle的文档:http://docs.oracle.com/javase/7/docs/technotes/guides/security/jsse/JSSERefGuide.html,SSL相关概念和协议内容在该文档中已经非常详细的介绍了,这里也不再赘述。

接下来直接上代码了。

首先需要实现一个X509TrustManager接口,这个接口是用来判断服务器提供的证书是否可以被客户端信任。这个类需要一个证书,我们可以通过浏览器的导出证书功能,将服务器上我们自己创建的证书导出在本地。在MyX509TrustManager的构造方法中,利用CertificateFactory生成一个Certificate实例。checkClientTrusted是用来检查客户端的证书的,这里我们只需要检测服务器端的证书就可以了,因此checkClientTrusted方法体就不添加代码了。checkServerTrusted是用来检查服务器端证书的合法性的,我们在这里对它进行一些处理。我这里用了一个非常简单的方法,就是比较服务器端发送来的证书和自己本地的证书是否一致。如果没有一样的证书,就直接抛出异常。

package com.uestc.test.upload;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

import javax.net.ssl.X509TrustManager;


public class MyX509TrustManager implements X509TrustManager {

	private Certificate cert = null;

	public MyX509TrustManager() {
		try {
			FileInputStream fis = new FileInputStream(
					"/Users/justyoung/Desktop/upload/Cloud3");
			BufferedInputStream bis = new BufferedInputStream(fis);

			CertificateFactory cf = CertificateFactory.getInstance("X.509");

			while (bis.available() > 0) {
				cert = cf.generateCertificate(bis);
//				System.out.println(cert.toString());
			}
            bis.close();
		} catch (CertificateException | IOException e) {
			e.printStackTrace();
		}
	}

	@Override
	public void checkClientTrusted(X509Certificate[] chain, String authType)
			throws CertificateException {
	}

	@Override
	public void checkServerTrusted(X509Certificate[] chain, String authType)
			throws CertificateException {
		for (X509Certificate cert : chain) {
			if (cert.toString().equals(this.cert.toString()))
				return;
		}
		throw new CertificateException("certificate is illegal");
	}

	@Override
	public X509Certificate[] getAcceptedIssuers() {
		return new X509Certificate[] { (X509Certificate) cert };
	}

}


然后,又实现了一个HostnameVerifier接口,这个类主要是在SSL握手时验证对方主机名称的,这样做的一个目的也是防止链接被重定向到其他的不安全的地址上去,并且若出现服务器证书上的Hostname和实际的URL不匹配时,也能做一些处理,否则会抛出这样的异常:javax.net.ssl.SSLPeerUnverifiedException: Host name '192.168.2.177' does not match the certificate subject provided by the peer,因此实现HostnameVerifier接口,我们能做一些hostname确认的工作,提高安全性。

package com.uestc.test;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;

public class MyVerifyHostname implements HostnameVerifier {

	@Override
	public boolean verify(String arg0, SSLSession arg1) {
		if (arg0.equals("192.168.2.177") || arg0.equals("cyber-space2015.imwork.net"))
			return true;
		else
			return false;
	}

}

最后就是利用HttpClient来完成Post请求的提交了。这里我们自定义了SSLContext,需要使用init方法,并传递进我们自己创建的TrustManager实例数组。然后利用HttpClients的custom方法自定义了一些参数,并生成HttpClient实例。其他代码就没什么特殊的了。

package com.uestc.test;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.BufferedHttpEntity;
import org.apache.http.entity.FileEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

public class UploadTest {
	private String host;
	private String cookie;
	private String path;
	private int port;
	private SSLContext sslContext;
	private X509TrustManager tm;
	private HttpClient httpClient;

	public UploadTest(String host, String cookie, String path, int port)
			throws Exception {
		this.host = host;
		this.cookie = cookie;
		this.path = path;
		this.port = port;
		sslContext = SSLContext.getInstance("TLS");
		tm = new MyX509TrustManager();
		sslContext.init(null, new TrustManager[] { tm },
				new java.security.SecureRandom());
		httpClient = HttpClients.custom()
				.setSSLHostnameVerifier(new MyVerifyHostname())
				.setSSLContext(sslContext).build();
	}

	public String uploadFile(String localPath, String filename)
			throws URISyntaxException, ClientProtocolException, IOException {

		URI uri = new URIBuilder().setScheme("https").setHost(host)
				.setPath(path).setParameter("filename", filename).setPort(port)
				.build();
		HttpPost httpPost = new HttpPost(uri);
		FileEntity fileEntity = new FileEntity(new File(localPath));
		fileEntity.setChunked(true);
		httpPost.setEntity(fileEntity);
		httpPost.addHeader("Cookie", cookie);
		HttpResponse response = httpClient.execute(httpPost);
		HttpEntity httpEntity = response.getEntity();
		httpEntity = new BufferedHttpEntity(httpEntity);
		String resultString = EntityUtils.toString(httpEntity);
		return resultString;
	}

	public static void main(String[] args) {
		try {
			UploadTest test = new UploadTest(
					"192.168.2.177",
					"XXXXX",
					"XXXXX", 443);
			String resultString = test.uploadFile(
					"/Users/justyoung/Desktop/upload/test.java", "mytest1");
			System.out.println(resultString);
		} catch (URISyntaxException | IOException e) {
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (KeyManagementException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

完。


转载于:https://my.oschina.net/boltwu/blog/550136

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值