漫话https编程

漫话https编程近期出于安全需要 把 app 中的 HTTP 协议升级为 https 双向验证接口

大家好,欢迎来到IT知识分享网。

长话短说,复杂的协议简单说。HTTPS(全称:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全为目标的HTTP通道,简单讲是HTTP的安全版。为啥安全呢,简单的说,他在建立连接前,会通过对互相持有的证书检验,对彼此身份进行检验。证书使用的非对称的RSA算法实现。分三种情况,一。如果是单向验证的话,在开放系统里,客户端会通过证书对服务的身份进行检验,如登录https://www.baidu.com,如果是http直接就建立连接了,如果是https,客户端会检查服务器端的证书是不是合法,是不是假冒的,防止钓鱼网站和木马。二。如果是单向验证的封闭系统,比如只对公司员工开放的内网服务,使用https就可以在服务器端对客户端证书检验,公司电脑可以正常访问,非公司电脑不建立连接。三。如果双向验证,那就严格了,不过原理同一二,只是把一二结合了起来。当然这是从编程角度来看的简化过程,是编写程序需要了解的基本知识。事实上https协议十分复杂,检验过程繁琐,除了用到不对称加密,可能还用到对称加密。但这些复杂的过程前辈们已经封装好了,不需要我们过分操心,我们只要准备好私钥,公钥,了解了他们的运用过程就可以写程序了。

通信过程用到证书,不可不说。用到的证书使用非对称加密算法生成。一套证书一般包含一对两个密钥,一个公钥和一个私钥,公钥给对方,私钥自己持有。这对密钥一个特点是公钥加密只能私钥解密,私钥加密只能公钥解密,公钥与公钥互相不能解密。单向验证一般只需要一个证书,双向验证需要两个证书。如果是类似百度开放系统,一般会对外公布他的公钥,客户端通过公钥在中介机构查询该证书是不是合法,拥有者是不是百度,如果是了,会有进一步验证,用该公钥加密信息传给这个网站,网站使用私钥解密,如果解密正常,一般认为网站就是百度,如假包换。如果有钓鱼网站下载百度的公钥,假冒百度,虽然第一步能通过,但因为他缺少百度私钥,无法解密公钥加密的信息,所以第二步就会被认出来是假的。单向的封闭系统原理一样,服务器会存储客户端的公钥,客户端保存私钥,通信时如果不是互相解密,则系统认为互相不可信任,则无法建立安全连接。双向验证需要两对证书,客户端存储自己的私钥和服务器的公钥,服务器存储自己的私钥和客户端公钥,客服端通过公钥验证服务器是否假冒,服务反过来再验证客户端是否可信。详细验证过程同单向。不赘述。

开放性的网站证书需要在中介机构申请,封闭性可申请,也可不申请,自己使用可以keytool工具根据需要生成。服务器和客户端都要保管好自己的私钥,私钥被别人获取,他们就可以假冒对方和你通信或者假冒你和另一方通信,系统将不再安全,所以一旦发现被偷盗或者遗失,就要快速废弃重新申请或者重新生成。

https编程就是把个人的证书和服务器的证书在https初始化时做为参数然后传递给服务器。证书各类非常多,应用场景也非常多,研究起来十分复杂。这里只做简单的研究。通常用于https通信的证书标准是X509,按编码格式分两大类,一类是二进制证书DER,一类是BASE编码的字符型证书PEM,按存储类型又可以分为以下:pfx/p12,jks,bks,pem,cer,der,cert等,大都和平台相关,BKS对应安卓,JKS用于JAVA默认,p12对应WIN,pem对应linux, cer对应服务器。这些格式之间都可以相互转换,而且可以包含相同内容的密钥。这意味着在不同两台,android,linux,mac,win下载,对于编程来说,哪怕使用的是跨平台的JAVA语言,考虑到apache,nignix等各种服务器架构,证书的初始化,加载方式可能都会不一样,一样的代码没办法通吃,需要根据服务器和客户端平台调整,这就是网上看到的程序在实用上有人可以成功,有人却总是失败,有时你在这个平台成功了,换台电脑或者平台又失败,再加上各种证书认证机构,所以最大的坑其实出现在证书异常上。所以在客户端编程上,对服务器证书是否假冒,对服务器身份认证上,编程访问可能会有很多种失败的因素,有些知名的浏览器也会对知名网站访问失败,可见这一切的坑有大呀。所以很多知名软件,app为了提高访问成功概率,在对https网站访问时,使用了跳过验证和全信任的策略,这虽然降低了安全性,但提升了用户体验,而且极大的降低了编程的难度。但这明显是以降低用户安全性为代价的,不可取。

常用的证书命令和转换命令:

1.生成带密钥的证书,设置别名,时效,其他使用默认,别名在证书操作过程十分重要:

keytool -genkey -alias certificatekey  -keyalg RSA -validity 700  -keystore keystore.jks

另一个比较懒人用的命令,可以减少输入,节省时间和出错之机会,保存成文件后,可以备忘证书名字,密码,私钥密码,期限之类,把其他参数改成自己需要的就好了:

keytool -genkey -keyalg RSA -keysize 512 -dname “cn=hyq,o=eagle,c=cn” -alias weblogic -keypass -keystore C:/mykeystore/weblogic.jks -storepass -validity 365

2.查看服务器端证书,这是个很有用的命令,连接失败时,可以通过查看服务器和客户端证书之区别

openssl s_client -connect www.baidu.com:443 –showcerts

3.查看证书,如果需要查看某个刚导入证书库的证书,可以使用下面一条验证证书是否导入成功

keytool -list –keystore client.jks

keytool -list -v –keystore client.jks

keytool -list -rfc –keystore client.jks

keytool -list –keystore client.jks -alias baiducom -storepass password

4.从浏览器导出的证书一般为pem,cer,der等格式,查看der,cer二进制格式证书和pem字符证书,pem可以使用CURL直接验证服务连接

openssl x509 -in baidu.cer -inform der -noout -text

也可以使用keytool看

keytool -printcert -rfc -file  baidu.cer

5.把cer证书导入java可信库

keytool -import –keystore “jre6\lib\security\cacerts”  –storepass changeitkeypass changeit -alias baiducomtrustcacerts -file baidu.cer

6.把cer证书导出

keytool -import –keystore “jre6\lib\security\cacerts”  –storepass changeitkeypass changeit -alias baiducom -file baidu2.cer

7.删除证书,担心证书库变乱,测试的证书就会删除

keytool -delete -alias baiducom –keystore “jre6\lib\security\cacerts” –storepass changeit

8.p12(pkcs12 )和jks转换,p12证书可以包含公钥和私钥,常用于个人或者客户端证书存储

keytool -importkeystore -srckeystore test.p12 -srcstoretype PKCS12 -deststoretype JKS -destkeystore test.jks

keytool -importkeystore -srckeystore test.jks -srcstoretype JKS -deststoretype PKCS12 -destkeystore test1.p12

9.p12包含私钥和公钥,可以用来作为客户端的证书,也可以导出pem,pem也可以转p12

openssl pkcs12 -clcerts -nokeys -in cert.pfx -out client.pem    #客户端个人证书的公钥  

openssl pkcs12 -nocerts -nodes -in cert.pfx -out key.pem #客户端个人证书的私钥

也可以转换为公钥与私钥合二为一的文件

openssl pkcs12 -in  cert.pfx -out all.pem -nodes                                   #客户端公钥与私钥,一起存在all.pem中

//PEM–>PKCS12

openssl pkcs12 -export -out cacert.p12 -in cacert.pem

//PKCS12–>CRT

openssl pkcs12 -in cacert.p12 -out mycerts.crt -nokeys -clcerts

//CRT–>CER

openssl x509 -inform pem -in mycerts.crt -outform der -out mycerts.cer

去除pem格式的key的密码

openssl rsa -in cert2.key -out cert22.key

合并pem格式输出pfx(p12)

openssl pkcs12 -export -inkey cert22.key -in cert2.crt -out cert2.pfx

可以使用curl调用PEM访问https来测试客户端证书

a、使用client.pem+key.pem

curl -k –cert client.pem –key key.pem https://www.xxxx.com

 

b、使用all.pem

curl -k –cert all.pem  https://www.xxxx.com

curl -d ‘@wxpay_refund.txt’ –cacert rootca.pem  -k –cert ./apiclient_cert.pem –key apiclient_key.pem https://api.mch.weixin..com/secapi/pay/refund

10.pem,cer,der.cert互相转换

openssl x509 -in cert22.pem -out cert22.crt
openssl x509 -in cert2.cer -out cert2.pem -outform PEM
openssl x509 -in cert22.pem -inform PEM -out cert22.der -outform DER
openssl x509 -in cert22.cer -inform DER -out cert22.pem -outform PEM

11JKS文件转换为KEYSTORE文件

//JKS—>P12

keytool -importkeystore -srckeystore D:\test.keystore -srcstoretype JKS -deststoretype PKCS12 -destkeystore test1.p12

//P12—->KEYSTORE

keytool -v -importkeystore -srckeystore D:\test.p12 -srcstoretype PKCS12 -destkeystore D:\test.keystore -deststoretype JKS

//keystore—>crt

keytool -export -alias test -file D:\test.crt -keystore D:\test.keystore

//CRT–>CER

openssl x509 -inform pem -in test.crt -outform der -out test.cer

//CER—>JKS

keytool -import -v -alias test -file test.cer -keystore test.jks -storepass -noprompt

12 cer转bks,bks用于安卓APP开发,主要是用于存储服务器端证书,需要bcprov-jdk16-141.jar

keytool -import -file service.cer -keystore client.bks -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider 

keytool -importcert -keystore keyStore.bks -file peer.cert -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider
eytool -importcert -trustcacerts -keystore trustStore.bks -file peer.cert -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider

13.一个好用的命令行工具importcert.sh,修改后可以用来导出bks,这个bcprov文件使用脚本不需要导入java库,因为导入好像会和android冲突

#!/bin/bash if [ -z $1 ]; then echo "Usage: importcert.sh <CA cert PEM file>" exit 1 fi CACERT=$1 BCJAR=bcprov-jdk16-146.jar TRUSTSTORE=res/raw/mytruststore.bks ALIAS=`openssl x509 -inform PEM -subject_hash -noout -in $CACERT` if [ -f $TRUSTSTORE ]; then rm $TRUSTSTORE || exit 1 fi echo "Adding certificate to $TRUSTSTORE..." keytool -import -v -trustcacerts -alias $ALIAS \ -file $CACERT \ -keystore $TRUSTSTORE -storetype BKS \ -providerclass org.bouncycastle.jce.provider.BouncyCastleProvider \ -providerpath $BCJAR \ -storepass secret echo "" echo "Added '$CACERT' with alias '$ALIAS' to $TRUSTSTORE...

单向验证,开放的服务器端验证,不需要验证客户端,只需要服务器端证书:

import java.io.File; import java.io.IOException; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import javax.net.ssl.SSLContext; import org.apache.http.HttpHost; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.protocol.HttpClientContext; import org.apache.http.config.Registry; import org.apache.http.config.RegistryBuilder; import org.apache.http.conn.routing.HttpRoute; import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.socket.PlainConnectionSocketFactory; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.TrustSelfSignedStrategy; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.ssl.SSLContexts; import org.apache.http.util.EntityUtils; public class OneTLSPool { public static CloseableHttpClient httpclient; // 获得池化得HttpClient static { // 设置truststore SSLContext sslcontext = null; try { sslcontext = SSLContexts .custom() .loadTrustMaterial( new File("D://https//ca//cl.jks"), "".toCharArray(), new TrustSelfSignedStrategy()).build(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } // 客户端支持TLSV1,TLSV2,TLSV3这三个版本 SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( sslcontext, new String[] { "TLSv1", "TLSv2", "TLSv3" }, null, SSLConnectionSocketFactory.getDefaultHostnameVerifier());// 客户端验证服务器身份的策略 // Create a registry of custom connection socket factories for supported // protocol schemes. Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder .<ConnectionSocketFactory> create() .register("http", PlainConnectionSocketFactory.INSTANCE) .register("https", new SSLConnectionSocketFactory(sslcontext)) .build(); PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager( socketFactoryRegistry); // Configure total max or per route limits for persistent connections // that can be kept in the pool or leased by the connection manager. connManager.setMaxTotal(100); connManager.setDefaultMaxPerRoute(10); // 个性化设置某个url的连接 connManager.setMaxPerRoute(new HttpRoute(new HttpHost("www.y.com", 80)), 20); httpclient = HttpClients.custom().setConnectionManager(connManager) .build(); } / * 单向验证且服务端的证书可信 * @throws IOException * @throws ClientProtocolException */ public static void oneWayAuthorizationAccepted() throws ClientProtocolException, IOException { // Execution context can be customized locally. HttpClientContext context = HttpClientContext.create(); HttpGet httpget = new HttpGet("https://www.yunzhu.com:8443"); // 设置请求的配置 RequestConfig requestConfig = RequestConfig.custom() .setSocketTimeout(5000).setConnectTimeout(5000) .setConnectionRequestTimeout(5000).build(); httpget.setConfig(requestConfig); System.out.println("executing request " + httpget.getURI()); CloseableHttpResponse response = httpclient.execute(httpget, context); try { System.out.println("----------------------------------------"); System.out.println(response.getStatusLine()); System.out.println(EntityUtils.toString(response.getEntity())); System.out.println("----------------------------------------"); // Once the request has been executed the local context can // be used to examine updated state and various objects affected // by the request execution. // Last executed request context.getRequest(); // Execution route context.getHttpRoute(); // Target auth state context.getTargetAuthState(); // Proxy auth state context.getTargetAuthState(); // Cookie origin context.getCookieOrigin(); // Cookie spec used context.getCookieSpec(); // User security token context.getUserToken(); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] a) throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException { oneWayAuthorizationAccepted(); } }

一个改进的单向验证

import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import org.apache.http.HttpHost; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.protocol.HttpClientContext; import org.apache.http.config.Registry; import org.apache.http.config.RegistryBuilder; import org.apache.http.conn.routing.HttpRoute; import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.socket.PlainConnectionSocketFactory; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.TrustSelfSignedStrategy; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.ssl.SSLContexts; import org.apache.http.util.EntityUtils; public class OneTLSPool { public static CloseableHttpClient httpclient; public static final String KEY_STORE_TRUST_PATH = "D://https//ca//cl.jks"; // truststore的路径 public static final String KEY_STORE_TYPE_JKS = "jks"; // truststore的类型 private static final String KEY_STORE_TRUST_PASSWORD = ""; // truststore的密码 // 获得池化得HttpClient static { SSLContext sslcontext = null; try { // 设置truststore KeyStore trustStore = KeyStore.getInstance(KEY_STORE_TYPE_JKS); InputStream tsIn = new FileInputStream(new File(KEY_STORE_TRUST_PATH)); try { trustStore.load(tsIn, KEY_STORE_TRUST_PASSWORD.toCharArray()); } finally { try { tsIn.close(); } catch (Exception ignore) { } } sslcontext = SSLContexts.custom().loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()).build(); //解决jdk7的ssl的自签名会有问题的bug,如果不是jdk7,则下面的代码可以没有 //bug地址:http://bugs.java.com/bugdatabase/view_bug.do?bug_id= X509TrustManager xtm = new X509TrustManager(){ //创建TrustManager public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {} public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {} public X509Certificate[] getAcceptedIssuers() { return null; //return new java.security.cert.X509Certificate[0]; } }; sslcontext.init(null, new TrustManager[]{xtm}, null); //解决bug结束 } catch (Exception e) { e.printStackTrace(); } // 客户端支持TLSV1,TLSV2,TLSV3这三个版本 SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1", "TLSv2", "TLSv3" }, null, SSLConnectionSocketFactory.getDefaultHostnameVerifier());// 客户端验证服务器身份的策略 // Create a registry of custom connection socket factories for supported // protocol schemes. Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create() .register("http", PlainConnectionSocketFactory.INSTANCE) .register("https", new SSLConnectionSocketFactory(sslcontext)).build(); PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); // Configure total max or per route limits for persistent connections // that can be kept in the pool or leased by the connection manager. connManager.setMaxTotal(100); connManager.setDefaultMaxPerRoute(10); // 个性化设置某个url的连接 connManager.setMaxPerRoute(new HttpRoute(new HttpHost("www.y.com", 80)), 20); httpclient = HttpClients.custom().setConnectionManager(connManager).build(); } / * 单向验证且服务端的证书可信 * * @throws IOException * @throws ClientProtocolException */ public static void oneWayAuthorizationAccepted() throws ClientProtocolException, IOException { // Execution context can be customized locally. HttpClientContext context = HttpClientContext.create(); HttpGet httpget = new HttpGet("https://www.yunzhu.com:8443"); // 设置请求的配置 RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(5000).setConnectTimeout(5000) .setConnectionRequestTimeout(5000).build(); httpget.setConfig(requestConfig); System.out.println("executing request " + httpget.getURI()); CloseableHttpResponse response = httpclient.execute(httpget, context); try { System.out.println("----------------------------------------"); System.out.println(response.getStatusLine()); System.out.println(EntityUtils.toString(response.getEntity())); System.out.println("----------------------------------------"); // Once the request has been executed the local context can // be used to examine updated state and various objects affected // by the request execution. // Last executed request context.getRequest(); // Execution route context.getHttpRoute(); // Target auth state context.getTargetAuthState(); // Proxy auth state context.getTargetAuthState(); // Cookie origin context.getCookieOrigin(); // Cookie spec used context.getCookieSpec(); // User security token context.getUserToken(); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] a) throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException { oneWayAuthorizationAccepted(); } }

双向验证,客户端使用p12,服务器使用jks

import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import javax.net.ssl.SSLContext; import org.apache.http.HttpHost; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.protocol.HttpClientContext; import org.apache.http.config.Registry; import org.apache.http.config.RegistryBuilder; import org.apache.http.conn.routing.HttpRoute; import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.socket.PlainConnectionSocketFactory; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.TrustSelfSignedStrategy; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.ssl.SSLContexts; import org.apache.http.util.EntityUtils; public class DoubleWayTlsPool { public static CloseableHttpClient httpclient; public static final String KEY_STORE_TRUST_PATH = "D://https//ca//cl.jks"; // truststore的路径 public static final String KEY_STORE_TYPE_JKS = "jks"; // truststore的类型 private static final String KEY_STORE_TRUST_PASSWORD = ""; // truststore的密码 public static final String KEY_STORE_CLIENT_PATH="D://https//client//client.p12"; public static final String KEY_STORE_TYPE_P12="PKCS12"; private static final String KEY_STORE_PASSWORD=""; // 获得池化得HttpClient static { SSLContext sslcontext = null; try { // 设置truststore KeyStore trustStore = KeyStore.getInstance(KEY_STORE_TYPE_JKS); KeyStore keyStore = KeyStore.getInstance(KEY_STORE_TYPE_P12); InputStream ksIn = new FileInputStream(KEY_STORE_CLIENT_PATH); InputStream tsIn = new FileInputStream(new File(KEY_STORE_TRUST_PATH)); try { keyStore.load(ksIn, KEY_STORE_PASSWORD.toCharArray()); trustStore.load(tsIn, KEY_STORE_TRUST_PASSWORD.toCharArray()); } finally { try { ksIn.close(); tsIn.close(); } catch (Exception e) { e.printStackTrace(); } } sslcontext = SSLContexts.custom().loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()).loadKeyMaterial(keyStore, KEY_STORE_PASSWORD.toCharArray()).build(); //下面的代码可以动态的设置握手验证证书的策略,可以不用手工导入证书,而只要程序控制即可 //bug地址:http://bugs.java.com/bugdatabase/view_bug.do?bug_id= /* X509TrustManager xtm = new X509TrustManager(){ //创建TrustManager public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {} public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {} public X509Certificate[] getAcceptedIssuers() { return null; //return new java.security.cert.X509Certificate[0]; } }; sslcontext.init(null, new TrustManager[]{xtm}, null);*/ //解决bug结束 } catch (Exception e) { e.printStackTrace(); } // 客户端支持TLSV1,TLSV2,TLSV3这三个版本 SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1", "TLSv2", "TLSv3" }, null, SSLConnectionSocketFactory.getDefaultHostnameVerifier());// 客户端验证服务器身份的策略 // Create a registry of custom connection socket factories for supported // protocol schemes. Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create() .register("http", PlainConnectionSocketFactory.INSTANCE) .register("https", new SSLConnectionSocketFactory(sslcontext)).build(); PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); // Configure total max or per route limits for persistent connections // that can be kept in the pool or leased by the connection manager. connManager.setMaxTotal(100); connManager.setDefaultMaxPerRoute(10); // 个性化设置某个url的连接 connManager.setMaxPerRoute(new HttpRoute(new HttpHost("www.y.com", 80)), 20); httpclient = HttpClients.custom().setConnectionManager(connManager).build(); } / * 单向验证且服务端的证书可信 * * @throws IOException * @throws ClientProtocolException */ public static void doubleWayAuthorizationAccepted() throws ClientProtocolException, IOException { // Execution context can be customized locally. HttpClientContext context = HttpClientContext.create(); HttpGet httpget = new HttpGet("https://www.yunzhu.com:8443"); // 设置请求的配置 RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(5000).setConnectTimeout(5000) .setConnectionRequestTimeout(5000).build(); httpget.setConfig(requestConfig); System.out.println("executing request " + httpget.getURI()); CloseableHttpResponse response = httpclient.execute(httpget, context); try { System.out.println("----------------------------------------"); System.out.println(response.getStatusLine()); System.out.println(EntityUtils.toString(response.getEntity())); System.out.println("----------------------------------------"); // Once the request has been executed the local context can // be used to examine updated state and various objects affected // by the request execution. // Last executed request context.getRequest(); // Execution route context.getHttpRoute(); // Target auth state context.getTargetAuthState(); // Proxy auth state context.getTargetAuthState(); // Cookie origin context.getCookieOrigin(); // Cookie spec used context.getCookieSpec(); // User security token context.getUserToken(); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] a) throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException { doubleWayAuthorizationAccepted(); } }

如果连接出错,很可能是证书出错,需要把服务器端证书导入java证书库。也可以使用下面方法,在运行时加载库

  1. Properties systemProps = System.getProperties();  
  2. systemProps.put( “javax.net.ssl.trustStore”“/path/to/yourTruststore.jks”);  
  3. systemProps.put( “javax.net.ssl.trustStorePassword”“trustStorePassword”);  
  4. System.setProperties(systemProps);  

也可以使用命令运行参数加载证书

  1. java -Djavax.net.ssl.trustStore=yourTruststore.jks -Djavax.net.ssl.trustStorePassword= YourApp  

导出服务器端证书可以使用浏览器,导出之后需要设置导入证书,过程简单,但有些人总是搞不好,有位大牛提供一个脚本,运行后可以把服务器直接下载导入java证书库,其他就不用管了,直接使用就行了

import java.io.*; import java.net.URL; import java.security.*; import java.security.cert.*; import javax.net.ssl.*; public class InstallCert { public static void main(String[] args) throws Exception { String host; int port; char[] passphrase; if ((args.length == 1) || (args.length == 2)) { String[] c = args[0].split(":"); host = c[0]; port = (c.length == 1) ? 443 : Integer.parseInt(c[1]); String p = (args.length == 1) ? "changeit" : args[1]; passphrase = p.toCharArray(); } else { System.out.println("Usage: java InstallCert <host>[:port] [passphrase]"); return; } File file = new File("jssecacerts"); if (file.isFile() == false) { char SEP = File.separatorChar; File dir = new File(System.getProperty("java.home") + SEP + "lib" + SEP + "security"); file = new File(dir, "jssecacerts"); if (file.isFile() == false) { file = new File(dir, "cacerts"); } } System.out.println("Loading KeyStore " + file + "..."); InputStream in = new FileInputStream(file); KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); ks.load(in, passphrase); in.close(); SSLContext context = SSLContext.getInstance("TLS"); TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(ks); X509TrustManager defaultTrustManager = (X509TrustManager)tmf.getTrustManagers()[0]; SavingTrustManager tm = new SavingTrustManager(defaultTrustManager); context.init(null, new TrustManager[] {tm}, null); SSLSocketFactory factory = context.getSocketFactory(); System.out.println("Opening connection to " + host + ":" + port + "..."); SSLSocket socket = (SSLSocket)factory.createSocket(host, port); socket.setSoTimeout(10000); try { System.out.println("Starting SSL handshake..."); socket.startHandshake(); socket.close(); System.out.println(); System.out.println("No errors, certificate is already trusted"); } catch (SSLException e) { System.out.println(); e.printStackTrace(System.out); } X509Certificate[] chain = tm.chain; if (chain == null) { System.out.println("Could not obtain server certificate chain"); return; } BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); System.out.println(); System.out.println("Server sent " + chain.length + " certificate(s):"); System.out.println(); MessageDigest sha1 = MessageDigest.getInstance("SHA1"); MessageDigest md5 = MessageDigest.getInstance("MD5"); for (int i = 0; i < chain.length; i++) { X509Certificate cert = chain[i]; System.out.println (" " + (i + 1) + " Subject " + cert.getSubjectDN()); System.out.println(" Issuer " + cert.getIssuerDN()); sha1.update(cert.getEncoded()); System.out.println(" sha1 " + toHexString(sha1.digest())); md5.update(cert.getEncoded()); System.out.println(" md5 " + toHexString(md5.digest())); System.out.println(); } System.out.println("Enter certificate to add to trusted keystore or 'q' to quit: [1]"); String line = reader.readLine().trim(); int k; try { k = (line.length() == 0) ? 0 : Integer.parseInt(line) - 1; } catch (NumberFormatException e) { System.out.println("KeyStore not changed"); return; } X509Certificate cert = chain[k]; String alias = host + "-" + (k + 1); ks.setCertificateEntry(alias, cert); OutputStream out = new FileOutputStream("jssecacerts"); ks.store(out, passphrase); out.close(); System.out.println(); System.out.println(cert); System.out.println(); System.out.println ("Added certificate to keystore 'jssecacerts' using alias '" + alias + "'"); } private static final char[] HEXDIGITS = "0abcdef".toCharArray(); private static String toHexString(byte[] bytes) { StringBuilder sb = new StringBuilder(bytes.length * 3); for (int b : bytes) { b &= 0xff; sb.append(HEXDIGITS[b >> 4]); sb.append(HEXDIGITS[b & 15]); sb.append(' '); } return sb.toString(); } private static class SavingTrustManager implements X509TrustManager { private final X509TrustManager tm; private X509Certificate[] chain; SavingTrustManager(X509TrustManager tm) { this.tm = tm; } public X509Certificate[] getAcceptedIssuers() { throw new UnsupportedOperationException(); } public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { throw new UnsupportedOperationException(); } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { this.chain = chain; tm.checkServerTrusted(chain, authType); } } } 

如果你仍然没有办法访问成功https网站,可以参考附录的一些分析方法查找原因。如果在某些平台不成功,如果安全性要求不高,可以考虑使用能用证书和设置全信任的方法解决。

X509TrustManager[] xtms = new X509TrustManager[] {new X509TrustManager() { // 创建TrustManager @Override public void checkClientTrusted(java.security.cert.X509Certificate[] arg0, String arg1) throws CertificateException { // TODO Auto-generated method stub } @Override public void checkServerTrusted(java.security.cert.X509Certificate[] arg0, String arg1) throws CertificateException { // TODO Auto-generated method stub } @Override public java.security.cert.X509Certificate[] getAcceptedIssuers() { // TODO Auto-generated method stub return null; } }};

参考:

https://www.cnblogs.com/YDDMAX/p/5380131.html

https://blog.csdn.net/fenglibing/article/details/

https://blog.csdn.net/joker_honey/article/details/

https://blog.csdn.net/u0/article/details/

提供证书转换的网站

https://myssl.com/cert_convert.html

证书转换方法:

https://blog.csdn.net/ONLYMETAGAIN/article/details/

一些问题解决策略

一些加载证书方式


免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/145145.html

(0)
上一篇 2025-04-21 20:15
下一篇 2025-04-21 20:20

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信