使用HttpClient4.5实现HTTPS的双向认证

 

 说明:本文主要是在平时接口对接开发中遇到的为保证传输安全的情况特要求使用https进行交互的情况下,使用httpClient4.5版本对HTTPS的双向验证的  功能的实现
    首先,老生常谈,文章将按照哲学三部曲来解答什么是https,为什么要使用https,httpClient怎么实现https及双向验证。
    问题1:什么是https?
    https:安全的超文本传输协议;其实质是
    加密+认证+完整性保护的HTTP,
    也就是说是http的安全版本,https由http进行通信,但利用SSL/TLS协议来加密数据包,并提供对网站服务器的身份认证,保护交换数据的隐私与完整性 。
    问题2:为什么要使用https协议?
    没有任何一个东西是完美的,总所周知,https出现以前,哪怕是直到现在我们见到更多的还是http协议,那么为什么我们要使用https协议呢?一般来说https是安全的http协议,我们更多的用于支付场景中,https协议主要针对解决http协议以下不足:
    1.http使用明文(不加密)通信,内容可能会被窃听
    2.不对通信方身份进行认证,可能遭遇伪装攻击
    3.无法证明报文的完整性(即准确性),报文可能已被篡改
    同样的虽然https解决了HTTP存在的一些问题,但是https的本质是将http的通信接口加入了SSL/TLS协议进行加密处理,加密通信会消耗更多的cup以及内存资源。同样在三次握手事,相对效率会变低,除此之外,要进行https通信,证书是必不可少的。而是用证书必须向认证机构(CA)购买。
    问题3:httpClient怎么实现https及双向验证?
    对接的服务端发送过来的证书是pfx格式的证书,正常来讲pfx格式证书是包含了公钥/私钥/证书信息等的PKCS12证书,然而直接使用pfx证书作为keyStore却一直报错no trusted certificate error,因此在网上查询了一天,终于把这个问题解决了,解决方案如下:
    先将.pfx文件转为.cer文件,再将.cer文件使用keytool工具导入$JAVA_HOME/jre/lib/security/cacerts中,cacerts证书库的默认密码为changeit;
    1.pfx文件转为cer文件的方法:
        1.使用IE浏览器
    2.将.cer文件使用keytool工具导入cacerts证书库
        1.keytool -import -alias testCer -keystore cacerts -file C:\Users\admin\Desktop\bcTest.cer
    3.java代码中的文件配置
        初始化keyStore:为pfx证书路径与密码,策略为PKCS12
        初始化trustStore:为cacerts证书库地址,策略为JKS,cacerts证书库默认密码为changeit
    Java代码实现:

  1     package com.test.sendhttps;
  2     
  3     import java.io.File;
  4     import java.io.FileInputStream;
  5     import java.io.FileNotFoundException;
  6     import java.io.IOException;
  7     import java.security.KeyManagementException;
  8     import java.security.KeyStore;
  9     import java.security.KeyStoreException;
 10     import java.security.NoSuchAlgorithmException;
 11     import java.security.UnrecoverableKeyException;
 12     import java.security.cert.CertificateException;
 13     import java.util.Iterator;
 14     import java.util.Map;
 15     import java.util.Set;
 16     import javax.net.ssl.KeyManager;
 17     import javax.net.ssl.KeyManagerFactory;
 18     import javax.net.ssl.SSLContext;
 19     import javax.net.ssl.TrustManager;
 20     import javax.net.ssl.TrustManagerFactory;
 21     import org.apache.commons.lang3.ObjectUtils;
 22     import org.apache.http.Header;
 23     import org.apache.http.HttpEntity;
 24     import org.apache.http.HttpStatus;
 25     import org.apache.http.client.methods.CloseableHttpResponse;
 26     import org.apache.http.client.methods.HttpPost;
 27     import org.apache.http.config.Registry;
 28     import org.apache.http.config.RegistryBuilder;
 29     import org.apache.http.conn.socket.ConnectionSocketFactory;
 30     import org.apache.http.conn.socket.PlainConnectionSocketFactory;
 31     import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
 32     import org.apache.http.entity.StringEntity;
 33     import org.apache.http.impl.client.CloseableHttpClient;
 34     import org.apache.http.impl.client.HttpClients;
 35     import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
 36     import org.apache.http.util.EntityUtils;
 37     import org.apache.log4j.Logger;
 38     import com.test.util.JsonUtils;
 39     import  com.test.util.PropertiesUtil;
 40     
 41     public class SendHttps {
 42         private static Logger log = Logger.getLogger(SendHttps.class);
 43         static String keyStorePath ;
 44         static String keyStorePassword ;
 45         static String keyStoreType ;
 46         static String trustStorePath ;
 47         static String trustStorePassword ;
 48         static String trustStoreType;
 49         static{
 50             PropertiesUtil proUtil;
 51             
 52             //配置文件读取
 53             try {
 54                 proUtil = new PropertiesUtil();
 55                 keyStorePath = proUtil.readValue("sslKeyStorePath");
 56                 keyStorePassword = proUtil.readValue("sslKeyStorePassword");
 57                 keyStoreType = proUtil.readValue("sslKeyStoreType");
 58                 trustStorePath = proUtil.readValue("sslTrustStore");
 59                 trustStorePassword = proUtil.readValue("sslTrustStorePassword");
 60                 trustStoreType = proUtil.readValue("sslTrustStoreType");
 61             } catch (IOException e) {
 62                 // TODO Auto-generated catch block
 63                 log.error("配置文件读取异常");
 64                 e.printStackTrace();
 65             }
 66         }
 67     
 68         public static String sendToHttps(String reqMsg, String url, Map<String, String> headMap) {
 69             log.info("keyFactory");
 70             //初始化KeyManager
 71             KeyManagerFactory keyFactory = null;
 72             try {
 73                 keyFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
 74                 KeyStore keystore = KeyStore.getInstance(keyStoreType); 
 75                 keystore.load(new FileInputStream(new File(keyStorePath)), null);  
 76                 keyFactory.init(keystore, keyStorePassword.toCharArray());
 77                 
 78             } catch (NoSuchAlgorithmException e) {
 79                 // TODO Auto-generated catch block
 80                 e.printStackTrace();
 81             } catch (KeyStoreException e) {
 82                 // TODO Auto-generated catch block
 83                 e.printStackTrace();
 84             } catch (CertificateException e) {
 85                 // TODO Auto-generated catch block
 86                 e.printStackTrace();
 87             } catch (FileNotFoundException e) {
 88                 // TODO Auto-generated catch block
 89                 e.printStackTrace();
 90             } catch (IOException e) {
 91                 // TODO Auto-generated catch block
 92                 e.printStackTrace();
 93             } catch (UnrecoverableKeyException e) {
 94                 // TODO Auto-generated catch block
 95                 e.printStackTrace();
 96             }  
 97             KeyManager[] keyManagers = keyFactory.getKeyManagers(); 
 98             //初始化Trust Manager
 99             log.info("keyFactory ="+keyFactory);  
100             TrustManagerFactory trustFactory = null;
101             
102                 try {
103                     trustFactory = TrustManagerFactory.getInstance("SunX509");
104                 } catch (NoSuchAlgorithmException e1) {
105                     // TODO Auto-generated catch block
106                     e1.printStackTrace();
107                 }
108             
109             KeyStore tsstore;
110             try {
111                 tsstore = KeyStore.getInstance(trustStoreType);
112                 tsstore.load(new FileInputStream(new File(trustStorePath)), trustStorePassword.toCharArray());   
113                 trustFactory.init(tsstore);  
114                 log.info("tsstore ="+tsstore+"   ||  trustFactory = "+trustFactory);
115             } catch (KeyStoreException e) {
116                 // TODO Auto-generated catch block
117                 e.printStackTrace();
118             } catch (NoSuchAlgorithmException e) {
119                 // TODO Auto-generated catch block
120                 e.printStackTrace();
121             } catch (CertificateException e) {
122                 // TODO Auto-generated catch block
123                 e.printStackTrace();
124             } catch (FileNotFoundException e) {
125                 // TODO Auto-generated catch block
126                 e.printStackTrace();
127             } catch (IOException e) {
128                 // TODO Auto-generated catch block
129                 e.printStackTrace();
130             }  
131             
132             TrustManager[] trustManagers = trustFactory.getTrustManagers(); 
133             log.info("trustManagers ="+trustManagers);  
134             //注册HtpClient
135             SSLContext sslContext = null;
136             try {
137                 sslContext = SSLContext.getInstance("TLS");
138                 sslContext.init(keyManagers, trustManagers, null); 
139             } catch (NoSuchAlgorithmException e) {
140                 // TODO Auto-generated catch block
141                 e.printStackTrace();
142             } catch (KeyManagementException e) {
143                 // TODO Auto-generated catch block
144                 e.printStackTrace();
145             } 
146             log.info("sslContext ="+sslContext);
147             
148             //设置规则限制
149             SSLConnectionSocketFactory ssf = new SSLConnectionSocketFactory(sslContext,
150                     new String[]{"TLSv1","TLSv1.1","TLSv1.2"},null,
151                     new HttpsHostnameVerifier());
152             //注册
153             Registry<ConnectionSocketFactory> socketFactoryRegistry = null;
154             socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create()
155                         .register("http", PlainConnectionSocketFactory.INSTANCE)
156                         .register("https", ssf).build();
157             //池化管理
158             PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
159             //创建httpClient
160             CloseableHttpClient httpClient;
161                 httpClient = HttpClients.custom().setConnectionManager(connManager).build(); 
162                 
163                 //设置httpPost
164                 HttpPost httpPost = new HttpPost(url);
165             if ((!headMap.isEmpty()) && (headMap.size() > 0)) {
166                   Set<String> keys = headMap.keySet();
167                   for (Iterator<String> i = keys.iterator(); i.hasNext(); ) {
168                     String key = ObjectUtils.toString(i.next());
169                     if("host".equals(key)){
170                         continue;
171                     }else{
172                         log.info("key="+key+",value="+(String)headMap.get(key));
173                         httpPost.addHeader(key, (String)headMap.get(key));
174                     }
175                   }
176                 }
177                 StringEntity reqEntity = new StringEntity(reqMsg, "UTF-8");
178         
179                 Header[] types = httpPost.getHeaders("Content-Type");
180                 if ((types == null) || (types.length < 1)) {
181                   httpPost.addHeader("Content-Type", "application/json;charset=utf-8");
182                 }
183         
184                 httpPost.setEntity(reqEntity);
185                 CloseableHttpResponse response;
186                 try {        
187                   response = httpClient.execute(httpPost);
188                 } catch (Exception e) {
189                   e.printStackTrace();
190                       return null;
191                 }
192                 int statusCode = response.getStatusLine().getStatusCode();
193                 if (statusCode != HttpStatus.SC_OK) {
194                   httpPost.abort();
195                   return JsonUtils.setError("Fail to connect . response code = " + statusCode + ". error.");
196                 }
197         
198                 HttpEntity entity = response.getEntity();
199                 String result = null;
200                 try {
201                   if (entity != null) {
202                     result = EntityUtils.toString(entity, "utf-8");
203                   }
204                   EntityUtils.consume(entity);
205                   response.close();
206                 } catch (Exception e) {
207                   log.error("Change charset to utf-8 error.");
208                   return JsonUtils.setError("Change charset to utf-8 error.");
209                 }
210                 return result;
211             }
212         }
213         

https设置主机名校验

 1         package com.test.sendhttps;
 2         
 3         import javax.net.ssl.HostnameVerifier;
 4         import javax.net.ssl.SSLSession;
 5         
 6         public class HttpsHostnameVerifier implements HostnameVerifier {
 7         
 8           /**
 9            * 验证对方主机名称 ,防止服务器证书上的Hostname和实际的URL不匹配
10            * 防止链接被重定向到其他的不安全的地址
11            */
12           @Override
13           public boolean verify(String hostname, SSLSession session) {
14             System.out.println("hostname = [" + hostname + "],session = [" + session.getPeerHost() + "]");
15             if (hostname.equals("地址") || session.equals("地址"))
16               return true;
17             else
18               return false;
19           }
20         }

配置信息 config.propertities:

sslKeyStorePath=pfx文件路径
sslKeyStorePassword=pfx文件密码
sslKeyStoreType=PKCS12
#jdk中的cacerts库地址
sslTrustStore=C:/Program Files/Java/jre7/lib/security/cacerts       
#cacerts库密码
sslTrustStorePassword=changeit
#cacerts库默认类型
sslTrustStoreType=JKS

后续更换证书操作
    查看cacerts证书库中的所有证书
    keytool -list -keystore cacerts
    删除证书库中别名为testCer的证书
    keytool -delete -alias testCer -keystore cacerts
    再次导入证书
    keytool -import -alias testCer -keystore cacerts -file C:\Users\admin\Desktop\testCer.cer

 

 以上即是所有内容,如有不正确之处,欢迎各位大神批评,斧正,谢谢

转载于:https://www.cnblogs.com/tydb/p/8708074.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值