百度百科对https的介绍:
HTTPS(全称:Hyper Text Transfer Protocol over Secure Socket Layer),以安全为目标HTTP简单来说,通道是HTTP的安全版。即HTTP下加入SSL层,HTTPS安全基础是SSL,因此,需要详细的加密内容SSL。 它是一个URI scheme(抽象标识符体系),句法类同http:体系。用于安全的HTTP数据传输。https:URL表明它已经HTTP,但HTTPS存在不同于HTTP默认端口和加密/身份验证层(在HTTP与TCP之间)。
HTTPS和HTTP的区别主要为以下四点:
一、https协议需要到ca申请证书,一般免费证书很少,需要付费。
二、http是超文本传输协议,信息是明文传输,https 它是安全的ssl加密传输协议。
三、http和https连接方式完全不同,端口也不同,前者是80,后者是443。
四、http连接简单,无状态;HTTPS协议是由SSL HTTP可加密传输和身份认证的网络协议比较http协议安全。
握手过程
为了便于更好的理解和理解SSL 这里重点介绍协议SSL 协议握手协议。SSL 该协议使用公钥加密技术和对称加密技术。虽然对称加密技术比公钥加密技术快,但公钥加密技术提供了更好的身份认证技术。SSL 握手协议对客户和服务器之间的身份认证非常有效,主要流程如下:
①客户端浏览器将客户端传输到服务器SSL 本协议的版本号、加密算法的类型、随机数量以及其他服务器和客户端之间通信所需的各种信息。
②将服务器传送到客户端SSL 本协议的版本号、加密算法的类型、随机数等相关信息,服务器还将自己的证书发送给客户端。
③客户使用服务器传输的信息来验证服务器的合法性。服务器的合法性包括:证书是否过期,服务器证书的发行CA 是否可靠,发行人证书的公钥是否能正确解开服务器证书的发行人数字签名如果合法性验证失败,通信将断开;如果合法性验证通过,第四步将继续。
④用户端随机生成一个对称密码,用于后续通信,然后使用服务器公钥服务器公钥从步骤)②在服务器证书中获得)加密,然后将加密后的预主密码传输给服务器。
⑤如果服务器要求客户的身份认证(握手过程中可选),用户可以建立随机数并签名数据,并将包含签名的随机数与客户自己的证书和加密的预主密码一起传输给服务器。
⑥如果服务器要求客户身份认证,服务器必须检查客户证书和随机签名数量的合法性。具体的合法性验证过程包括:客户证书的使用日期是否有效,并为客户提供证书CA 发行是否可靠CA 公钥能否正确解释客户证书的发行?CA 检查客户的证书是否在证书废止列表中(CRL)中。如果检查失败,通信将立即中断;如果验证通过,服务器将用自己的私钥解开加密的预主密码,然后执行一系列步骤生成主通信密码(客户端也将生成相同的主通信密码)。
⑦服务器和客户端用相同的主密码即“通话密码”,一个对称密钥用于SSL 协议安全数据通信加解密通信。SSL 数据通信的完整性应在通信过程中完成,以防止数据通信中的任何变化。
⑧客户端向服务器端发送信息,指示将使用以下数据通信步骤⑦主密码为对称密钥,并通知服务器客户端握手过程结束。
⑨服务器向客户端发送信息,指示将使用以下数据通信步骤⑦主密码为对称密钥,通知客户端服务器端握手过程结束。
⑩SSL 握手部分结束,SSL 从安全通道的数据通信开始,客户和服务器开始使用相同的对称密钥进行数据通信,并检查通信的完整性。
让我们写下来Https请求
String path = "https://www.baidu.com"; URL url = new URL(path); HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); InputStream is = conn.getInputStream(); String string = Utils.inputStream2String(is); System.out.println(string);
这可以正常访问,它将是百度html回来,那我们就回来吧。url把它改成别的看,把它改成我tomcat下一个工程网站已经放开(https配置,设置自签证书):https://localhost:8443/Test/myTest
String path = "https://localhost:8443/Test/myTest"; URL url = new URL(path); HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); InputStream is = conn.getInputStream(); String string = Utils.inputStream2String(is); System.out.println(string);
此时无法访问,报了一个javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target错误
那为什么呢?https可以自己访问tomcat的https不能访问?我们来看看百度百科。
信任主机
采用https服务器必须从CA (Certificate Authority)申请证明服务器用途类型的证书。该证书仅用于相应的服务器,客户端信任该主机。因此,所有银行系统网站的关键应用都是https 的。客户通过信任证书信任主机。其实效率很低,但银行更注重安全。
原来只有从CA默认情况下,机构申请的证书是可信的,客户端可以直接访问。而我自己tomcat使用下证java下的keytool工具不是自动生成的CA机构颁发的,默认不信任。那么,我们如何处理它,使它受到信任和访问呢?有两种方法:1。无条件设置所有信任证书。2.只设置信任和服务器jks对应的cer证书
1.无条件设置所有信任证书,但这样做是不安全的
public static void main(String[] args) { try { //初始化SSLContext SSLContext context = SSLContext.getInstance("TLS");//TLS和SSL都可以 //设置信任管理器 TrustManager[] managers = new TrustManager[]{new EmptyTrustManager()}; context.init(null, managers, null); //这个必须在HttpsURLConnection在生成对象之前设置 HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory()); String path = "https://localhost:8443/Test/myTest"; URL url = new URL(path); HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); //这时设置SSLSocketFactory没有用 //conn.setDefaultSSLSocketFactory(conn.getSSLSocketFactory()); InputStream is = conn.getInputStream(); String string = Utils.inputStream2String(is); System.out.println(string); } catch (Exception e) { e.printStackTrace(); } } static class EmptyTrustManager implements X509TrustManager { @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public X509Certificate[] getAcceptedIssuers() { return null; } }
2.只设置信任和服务器jks对应的cer证书。当您将项目的网络请求改为https后台哥们会给你一个xxx.cer证书,这个证书会和后台一起使用xxx.jks验证校验。我们可以将xxx.cer在工程中,读取文件,或将其打印成字符串,并将字符串放入代码中读取。以下是我以字符串的形式使用的。
static String chen = "-----BEGIN CERTIFICATE-----\n" "MIIDWTCCAkGgAwIBAgIENIaROTANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJDTjENMAsGA1UE" "CBMEY2hlbjENMAsGA1UEBxMEY2hlbjENMAsGA1UEChMEY2hlbjENMAsGA1UECxMEY2hlbjEMBAG"+
"A1UEAxMJbG9jYWxob3N0MB4XDTE3MDIxMzA5NDIzN1oXDTI2MTIyMzA5NDIzN1owXTELMAkGA1UE"+
"BhMCQ04xDTALBgNVBAgTBGNoZW4xDTALBgNVBAcTBGNoZW4xDTALBgNVBAoTBGNoZW4xDTALBgNV"+
"BAsTBGNoZW4xEjAQBgNVBAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC"+
"ggEBAKolNf440rZx58iz5P58VrWWPMQDZPMYuDDeZMENHRIUOu+PmjKwpmJUqVnKMvyGFj9VtoPE"+
"kZE7NQLzJ0FIfaTBLaHRTYLisk3qnVXgZyZq/rrLq935SURCRl76NP+pAyXBoWVUkvzRYwXfhFUi"+
"zO5yjH+ZFfQzjGWCugd8oYCLKmP+pJnlP/faNu7YDjL9JkOm6KiEnmkklkSJXrBBxmpsy0lSShwY"+
"rNoZ4wW8XwgbNdwjM+Z4+IeOD/gBZMSrI8n8TLKBFH6IydFJOkwhHO1BvdzNQHrcXF0CRqM5ctW4"+
"K7LXXE8OJg59b28ghdiqVAWRnSEyIYNgEBLkXnaU95UCAwEAAaMhMB8wHQYDVR0OBBYEFDt5QPgy"+
"T3yfkb9iXV92Wzo1YndfMA0GCSqGSIb3DQEBCwUAA4IBAQA9ZVQIGQERDvDlsjlSzmhcrX0Gpdxf"+
"kFmgXEc+Tck04l2VaT70YXYztcWTm8iPlxAOTAjxRE0syIbbAQ4UPba0hFINCPpvCD31ax3ukFUj"+
"NJH+rZUwo1HjV8qzKAA4nd3f31PRg3yyAzmgfAwqVNxiq26YVglvV6h3TnC6dgcnV4sejOvv5nTA"+
"7qc0cbQvGIEz4bEwIc+0l2/gwIoeUIquM6OAQTVzX9LuJ1aUTpenut+9G+vkEO3pfy4gdnOOXntW"+
"uzqhaUV9gxOd1et10n1pvDcYNG6hhAkvotgV8Pl+NnDZ22Hqin1XB1cOZv18zHxC9WThRma3VN0V"+
"z08eItRz\n"+
"-----END CERTIFICATE-----";
public static void main(String[] args) {
try {
ByteArrayInputStream baos = new ByteArrayInputStream(chen.getBytes());
SSLContext sslContext = getSSLContext(baos);
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
String path = "https://localhost:8443/Test/myTest";
URL url = new URL(path);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
//conn.setDefaultSSLSocketFactory(conn.getSSLSocketFactory());
InputStream is = conn.getInputStream();
String string = Utils.inputStream2String(is);
System.out.println(string);
} catch (Exception e) {
e.printStackTrace();
}
}
static SSLContext getSSLContext(InputStream is){
try{
//初始化SSLContext
SSLContext context = SSLContext.getInstance("TLS");//TLS和SSL都可以
// 1.导入证书
Certificate certificate = CertificateFactory.getInstance("X.509")
.generateCertificate(is);
// 2.证书导入密钥库
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null);
keyStore.setCertificateEntry("srca", certificate);
// 3.把密钥库放入信任管理器
TrustManagerFactory trustManagerFactory = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
// 4.生成信任管理器
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
// 将信任管理器设置到SSLContext
context.init(null, trustManagers, null);
return context;
}catch(Exception e){
e.printStackTrace();
}
return null;
}
如果url中的Hostname用的是IP则情况就不一样了,如果是String path = "https://127.0.0.1:8443/Test/myTest";再次访问的时候,会报javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative names present错误。
所以在HttpsURLConnection中的默认主机名验证的方法中应返回true以表示通过,
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
此设置应和SSLSocketFactory一样,在生成HttpsURLConnection之前设置,不然无效,所以main方法中代码应为
public static void main(String[] args) {
try {
ByteArrayInputStream baos = new ByteArrayInputStream(chen.getBytes());
SSLContext sslContext = getSSLContext(baos);
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
String path = "https://127.0.0.1:8443/Test/myTest";
URL url = new URL(path);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
//conn.setDefaultSSLSocketFactory(conn.getSSLSocketFactory());
InputStream is = conn.getInputStream();
String string = Utils.inputStream2String(is);
System.out.println(string);
} catch (Exception e) {
e.printStackTrace();
}
}
这时就可以正常访问了。 服务器端配置https
下面我们就来讲解如何生成自签名证书,和tomcat如何部署,完成这两步tomcat就可以使用https访问了,首先我们使用java自带的keytool工具生成证书,win+R打开运行,输入cmd打开cmd命令窗体,按照如下方式输入:
如何生成https证书:
1.生成jks,使用如下的命令就会生成一个chen.jks,密码为123456,jks是服务端tomcat配置https时使用的证书
C:\Program Files\Java\jdk1.7.0_67\bin>keytool -genkey -alias chen -keyalg
RSA -keystore C:\CJ\chen.jks -validity 3600 -storepass 123456
您的名字与姓氏是什么?
[Unknown]: localhost
您的组织单位名称是什么?
[Unknown]: chen
您的组织名称是什么?
[Unknown]: chen
您所在的城市或区域名称是什么?
[Unknown]: chen
您所在的省/市/自治区名称是什么?
[Unknown]: chen
该单位的双字母国家/地区代码是什么?
[Unknown]: CN
CN=localhost, OU=chen, O=chen, L=chen, ST=chen, C=CN是否正确?
[否]: y
输入 <chen_client> 的密钥口令
(如果和密钥库口令相同, 按回车):
再次输入新口令:
2.生成cer,使用如下命令和chen.jks就会生成一个chen.cer,xxx.cer是客户端https访问时用于与服务端jks进行校验的
C:\Program Files\Java\jdk1.7.0_67\bin>keytool -export -alias chen -file C
:\CJ\chen.cer -keystore C:\CJ\chen.jks -storepass 123456
存储在文件 <C:\CJ\chen_client.cer> 中的证书
3.打印cer,使用如下命令就可以打印cer中的字符串,就是上述提到的将cer打印成字符串,放入代码中,就不需要将xxx.cer放到工程中了。
C:\Program Files\Java\jdk1.7.0_67\bin>keytool -printcert -rfc -file C:\CJ\chen.cer
-----BEGIN CERTIFICATE-----
MIIDWTCCAkGgAwIBAgIENIaROTANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJDTjENMAsGA1UE
CBMEY2hlbjENMAsGA1UEBxMEY2hlbjENMAsGA1UEChMEY2hlbjENMAsGA1UECxMEY2hlbjESMBAG
A1UEAxMJbG9jYWxob3N0MB4XDTE3MDIxMzA5NDIzN1oXDTI2MTIyMzA5NDIzN1owXTELMAkGA1UE
BhMCQ04xDTALBgNVBAgTBGNoZW4xDTALBgNVBAcTBGNoZW4xDTALBgNVBAoTBGNoZW4xDTALBgNV
BAsTBGNoZW4xEjAQBgNVBAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAKolNf440rZx58iz5P58VrWWPMQDZPMYuDDeZMENHRIUOu+PmjKwpmJUqVnKMvyGFj9VtoPE
kZE7NQLzJ0FIfaTBLaHRTYLisk3qnVXgZyZq/rrLq935SURCRl76NP+pAyXBoWVUkvzRYwXfhFUi
zO5yjH+ZFfQzjGWCugd8oYCLKmP+pJnlP/faNu7YDjL9JkOm6KiEnmkklkSJXrBBxmpsy0lSShwY
rNoZ4wW8XwgbNdwjM+Z4+IeOD/gBZMSrI8n8TLKBFH6IydFJOkwhHO1BvdzNQHrcXF0CRqM5ctW4
K7LXXE8OJg59b28ghdiqVAWRnSEyIYNgEBLkXnaU95UCAwEAAaMhMB8wHQYDVR0OBBYEFDt5QPgy
T3yfkb9iXV92Wzo1YndfMA0GCSqGSIb3DQEBCwUAA4IBAQA9ZVQIGQERDvDlsjlSzmhcrX0Gpdxf
kFmgXEc+Tck04l2VaT70YXYztcWTm8iPlxAOTAjxRE0syIbbAQ4UPba0hFINCPpvCD31ax3ukFUj
NJH+rZUwo1HjV8qzKAA4nd3f31PRg3yyAzmgfAwqVNxiq26YVglvV6h3TnC6dgcnV4sejOvv5nTA
7qc0cbQvGIEz4bEwIc+0l2/gwIoeUIquM6OAQTVzX9LuJ1aUTpenut+9G+vkEO3pfy4gdnOOXntW
uzqhaUV9gxOd1et10n1pvDcYNG6hhAkvotgV8Pl+NnDZ22Hqin1XB1cOZv18zHxC9WThRma3VN0V
z08eItRz
-----END CERTIFICATE-----
4.tomcat服务器配置 ,在tomcat下的conf文件夹下的server.xml中配置
<Connector SSLEnabled="true" acceptCount="100" clientAuth="false"
disableUploadTimeout="true" enableLookups="true" keystoreFile="C:\\CJ\\chen.jks" keystorePass="123456" maxSpareThreads="75"
maxThreads="200" minSpareThreads="5" port="8443"
protocol="org.apache.coyote.http11.Http11NioProtocol" scheme="https"
secure="true" sslProtocol="TLS"
/>
在server.xml中的https默认配置的port为8443,你也可以修改,当你的电脑的8443端口被其他应用占用的时候,你就可以修改。这是重新启动tomcat时,这时你的服务器就可以使用https访问了。
这时该服务器用上面的网络请求就可以访问了。
双向证书验证 前面的https请求时,是服务器一个chen.jks,客户端一个chen.cer。那么双向证书验证,就还需要再次之前的配置上,再加上服务器一个chen_client.cer,客户端一个chen_client.jks。
重新生成一个证书 1.生成jks
C:\Program Files\Java\jdk1.7.0_67\bin>keytool -genkey -alias chen -keyalg
RSA -keystore C:\CJ\chen.jks -validity 3600 -storepass 123456
您的名字与姓氏是什么?
[Unknown]: localhost
您的组织单位名称是什么?
[Unknown]: chen
您的组织名称是什么?
[Unknown]: chen
您所在的城市或区域名称是什么?
[Unknown]: chen
您所在的省/市/自治区名称是什么?
[Unknown]: chen
该单位的双字母国家/地区代码是什么?
[Unknown]: CN
CN=localhost, OU=chen, O=chen, L=chen, ST=chen, C=CN是否正确?
[否]: y
输入 <chen_client> 的密钥口令
(如果和密钥库口令相同, 按回车):
再次输入新口令:
2.生成cer
C:\Program Files\Java\jdk1.7.0_67\bin>keytool -export -alias chen -file C
:\CJ\chen.cer -keystore C:\CJ\chen.jks -storepass 123456
存储在文件 <C:\CJ\chen_client.cer> 中的证书
需要将cer证书添加到jks中,不然,如果服务端使用cer证书,会报一个Invalid keystore format错误
C:\Program Files\Java\jdk1.7.0_67\bin>keytool -import -alias chen_client -file C
:\CJ\chen_client.cer -keystore C:\CJ\chen_client_for_server.jks
3.修改tomcat的配置文件
需要将之前的clientAuth="false"改为clientAuth="true",在增加一个字段truststoreFile="C:\\CJ\\chen_client_for_server.jks",指明jks的路径。
<Connector SSLEnabled="true" acceptCount="100" clientAuth="true"
disableUploadTimeout="true" enableLookups="true" keystoreFile="C:\\CJ\\chen.jks" keystorePass="123456" maxSpareThreads="75"
maxThreads="200" minSpareThreads="5" port="8443"
protocol="org.apache.coyote.http11.Http11NioProtocol" scheme="https"
secure="true" sslProtocol="TLS"
truststoreFile="C:\\CJ\\chen_client_for_server.jks"
/>
当是双向证书验证验证时,如果在tomcat/conf/sever.xml文件中的配置属性clientAuth="false",没有将其改为true,这是的双向证书验证验依然是单向的,客户端不做任何修改,https依然可以访问,如果将其改为true,就访问不了了。
这时重启服务器时,之前的https网络请求就请求不了了,报java.net.SocketException: Software caused connection abort: recv failed。这时我们需要修改一下网络请求代码,context.init(null, trustManagers, null);第一个参数是KeyManager[],是客户端的key,就是使用我们第二次生成的chen_client.jks,生成的KeyManager[]。添加如下代码:
//初始化keystore
KeyStore clientKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
InputStream iStream = new FileInputStream("chen_client.jks");
clientKeyStore.load(iStream, "123456".toCharArray());
//将keystore放入密钥管理器
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(clientKeyStore, "123456".toCharArray());
//生成密钥管理器
KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();
// 将信任管理器设置到SSLContext
context.init(keyManagers, trustManagers, null);
这时就可以进行网络请求了(java平台),客户端和服务器就是双向证书验证方式,网络请求就会更加的安全可靠。(如果是双向证书验证的tomcat,如果客户端不给kayManagers就会报 javax.net.ssl.SSLException: Connection closed by peer 错误)
这时我们将代码移植到Android工程中,跑起来,访问网络失败,报java.io.IOException: Wrong version of key store.异常。这是因为Java平台默认识别jks格式的证书文件,但是android平台只识别bks格式的证书文件。所以这时我们就需要将jks格式转成bks格式,我们可以使用Portecle工具进行转换:
下载。下载完之后解压,里面有一个Portecle.jar,在DOS界面,使用jave -jar Portecle.jar打开图形界面,操作步骤:1.File->Open Keystore File->选择chen_client.jks->输入密码 2.Tools->Change Keystore Type->BKS->输入密码 3.Save Keystore->选择保存路径(命名:chen_client.bks)。然后将Android工程中的chen_client.jks替换为chen_client.bks。重新运行Android项目,就可以正常访问了。Android中的完整代码如下: URLConnection双向证书验证的https请求:
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import com.tydz.taoyuan.R;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
public class HttpsActivity extends AppCompatActivity {
static Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
mTextView.setText(msg.obj.toString());
}
};
static String chen = "-----BEGIN CERTIFICATE-----\n" +
"MIIDWTCCAkGgAwIBAgIEcWnCMTANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJDTjENMAsGA1UE\n" +
"CBMEY2hlbjENMAsGA1UEBxMEY2hlbjENMAsGA1UEChMEY2hlbjENMAsGA1UECxMEY2hlbjESMBAG\n" +
"A1UEAxMJbG9jYWxob3N0MB4XDTE3MDIxMzE0MTIzNVoXDTI2MTIyMzE0MTIzNVowXTELMAkGA1UE\n" +
"BhMCQ04xDTALBgNVBAgTBGNoZW4xDTALBgNVBAcTBGNoZW4xDTALBgNVBAoTBGNoZW4xDTALBgNV\n" +
"BAsTBGNoZW4xEjAQBgNVBAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n" +
"ggEBAOCj9+qaE/DcDtJnEpeSc0+byTO3/yM673C4sgax7n4lCnjtmhgqiwASTCOnEMRJ6llmo/M8\n" +
"+msz9i+1vE4lte7AkZ/3Wfu04BXq9wmDlVNWU3kU6TfZMUhqifTvRC6zQmfJaBdS6SSfmBslrUUC\n" +
"ntD19vvGRLPkEt05s0itG54ex41fSgA4pBtj6qpBjLMS/03fCD6y3YdL+r0dN6bDxAuLo+2flJEy\n" +
"9CrnXEzLcZ172zD+5mfvhFI7F1fF1kdjT4pNi22sap5AOFZazaK7snq03cLTchC7yBwcPCJ6IqzY\n" +
"Yw6bVb79cj6nntbTb6lsrL7wv2kR8ubtiRTrrtCP2YMCAwEAAaMhMB8wHQYDVR0OBBYEFF5ZFY02\n" +
"FejgLSsO9DOZppwUhGS4MA0GCSqGSIb3DQEBCwUAA4IBAQCNg76X3tRCtnDi7cT5M8ADMzSUlYvA\n" +
"CaVYKQ+lB3WBLuqR3wVVJ/zeSGqiR4F59cj6Oij+fk5Fu05n+0nXX/sdirf2RTW1eaA+SzPYXdgA\n" +
"0u8XJdaPu58q0GCPFpUv24ljzQEr/hZBS9HWlHmkgByecpgrrToOc3jJNIQr8g1NVO/b8RCBFyx8\n" +
"Ax+Ytp8XNGKbmMnXifBxBnhMCT0DptmZuYsTacZ5qLqEhszChYSM3drYhoNId1HlLLeQbUumbB/8\n" +
"N1BVVH2LYPTJgKdXTQAzTWiUAss/HD78fe30qI3MDrZ1h4eF+vCHqOwAOiLxQ0Rpb5oMsVCblmoR\n" +
"+ool1ljG\n" +
"-----END CERTIFICATE-----";
private static TextView mTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_https);
mTextView = (TextView) findViewById(R.id.textview);
new Thread(){
@Override
public void run() {
super.run();
try {
net();
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
}
private void net() throws Exception{
ByteArrayInputStream baos = new ByteArrayInputStream(chen.getBytes());
//InputStream iStream = new FileInputStream("chen_client.jks");
InputStream iStream = getAssets().open("chen_client.bks");
SSLContext sslContext = getSSLContext(baos,iStream);
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
String path = "https://10.0.2.2:8444/OkHttp/text";
URL url = new URL(path);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
//********************************
//POST请求
/*
conn.addRequestProperty("Content-Type", "application/json");
conn.addRequestProperty("Connection", "Keep-Alive");// 维持长连接
conn.addRequestProperty("Charset", "UTF-8");
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setRequestMethod("POST");
OutputStream outputStream = conn.getOutputStream();
outputStream.write("{\"name\":chen}".getBytes("UTF-8"));
outputStream.flush();
outputStream.close();
*/
//************************************
//conn.setDefaultSSLSocketFactory(conn.getSSLSocketFactory());
InputStream is = conn.getInputStream();
String string = inputStream2String(is);
System.out.println(string);
sendMsg(string);
}
private void sendMsg(String msg){
Message message = mHandler.obtainMessage();
message.obj = msg;
mHandler.sendMessage(message);
}
SSLContext getSSLContext(InputStream cer,InputStream bks){
try{
//初始化SSLContext
SSLContext context = SSLContext.getInstance("TLS");//TLS和SSL都可以
// 1.导入证书
Certificate certificate = CertificateFactory.getInstance("X.509")
.generateCertificate(cer);
// 2.证书导入密钥库
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null);
keyStore.setCertificateEntry("srca", certificate);
// 3.把密钥库放入信任管理器
TrustManagerFactory trustManagerFactory = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
// 4.生成信任管理器
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
//初始化keystore
KeyStore clientKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
clientKeyStore.load(bks, "123456".toCharArray());
//将keystore放入密钥管理器
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(clientKeyStore, "123456".toCharArray());
//生成密钥管理器
KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();
// 将信任管理器设置到SSLContext
context.init(keyManagers, trustManagers, null);
return context;
}catch(Exception e){
e.printStackTrace();
}
return null;
}
public static String inputStream2String(InputStream in) throws IOException {
int len = -1;
byte[] buffer = new byte[1024];
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while ((len = in.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
baos.close();
return baos.toString("UTF-8");
}
}
Volley双向证书验证的https请求: Volley因为API>=9底层的就是用HttpsURLConnection,HttpsURLConnection实现的,所以volley实现https的代码可以参考java的HttpsURLConnection的,volley的http请求时的请求队列:RequestQueue queue = Volley.newRequestQueue(getApplication());,newRequestQueue(Context)还有一个重载方法newRequestQueue(Context context, HttpStack stack),这个就是https的入口,HurlStack构造中就有一个参数传的就是SSLSocketFactory,所以volley的https的请求代码如下: import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.HurlStack;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
public class MainActivity extends AppCompatActivity {
static Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
mTextView.setText(msg.obj.toString());
}
};
static String chen = "-----BEGIN CERTIFICATE-----\n" +
"MIIDWTCCAkGgAwIBAgIEcWnCMTANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJDTjENMAsGA1UE\n" +
"CBMEY2hlbjENMAsGA1UEBxMEY2hlbjENMAsGA1UEChMEY2hlbjENMAsGA1UECxMEY2hlbjESMBAG\n" +
"A1UEAxMJbG9jYWxob3N0MB4XDTE3MDIxMzE0MTIzNVoXDTI2MTIyMzE0MTIzNVowXTELMAkGA1UE\n" +
"BhMCQ04xDTALBgNVBAgTBGNoZW4xDTALBgNVBAcTBGNoZW4xDTALBgNVBAoTBGNoZW4xDTALBgNV\n" +
"BAsTBGNoZW4xEjAQBgNVBAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n" +
"ggEBAOCj9+qaE/DcDtJnEpeSc0+byTO3/yM673C4sgax7n4lCnjtmhgqiwASTCOnEMRJ6llmo/M8\n" +
"+msz9i+1vE4lte7AkZ/3Wfu04BXq9wmDlVNWU3kU6TfZMUhqifTvRC6zQmfJaBdS6SSfmBslrUUC\n" +
"ntD19vvGRLPkEt05s0itG54ex41fSgA4pBtj6qpBjLMS/03fCD6y3YdL+r0dN6bDxAuLo+2flJEy\n" +
"9CrnXEzLcZ172zD+5mfvhFI7F1fF1kdjT4pNi22sap5AOFZazaK7snq03cLTchC7yBwcPCJ6IqzY\n" +
"Yw6bVb79cj6nntbTb6lsrL7wv2kR8ubtiRTrrtCP2YMCAwEAAaMhMB8wHQYDVR0OBBYEFF5ZFY02\n" +
"FejgLSsO9DOZppwUhGS4MA0GCSqGSIb3DQEBCwUAA4IBAQCNg76X3tRCtnDi7cT5M8ADMzSUlYvA\n" +
"CaVYKQ+lB3WBLuqR3wVVJ/zeSGqiR4F59cj6Oij+fk5Fu05n+0nXX/sdirf2RTW1eaA+SzPYXdgA\n" +
"0u8XJdaPu58q0GCPFpUv24ljzQEr/hZBS9HWlHmkgByecpgrrToOc3jJNIQr8g1NVO/b8RCBFyx8\n" +
"Ax+Ytp8XNGKbmMnXifBxBnhMCT0DptmZuYsTacZ5qLqEhszChYSM3drYhoNId1HlLLeQbUumbB/8\n" +
"N1BVVH2LYPTJgKdXTQAzTWiUAss/HD78fe30qI3MDrZ1h4eF+vCHqOwAOiLxQ0Rpb5oMsVCblmoR\n" +
"+ool1ljG\n" +
"-----END CERTIFICATE-----";
private static TextView mTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.textview);
}
public void click(View view){
new Thread(){
@Override
public void run() {
super.run();
try {
volley();
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
}
void volley() throws Exception{
String path = "https://10.0.2.2:8444/OkHttp/text";
ByteArrayInputStream baos = new ByteArrayInputStream(chen.getBytes());
//InputStream iStream = new FileInputStream("chen_client.jks");
InputStream iStream = getAssets().open("chen_client.bks");
SSLContext sslContext = getSSLContext(baos,iStream);
//SSLSocketFactory在HurlStack内部已经实现
//HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
HurlStack hurlStack = new HurlStack(null,sslContext.getSocketFactory());
RequestQueue queue = Volley.newRequestQueue(getApplication(),hurlStack);
//get
StringRequest request = new StringRequest(path, new Response.Listener<String>() {
@Override
public void onResponse(String response) {
sendMsg(response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
error.printStackTrace();
sendMsg(error.toString());
}
});
//post
/*
Map map = new HashMap<>();
map.put("userName", "183********");
map.put("password", "111111");
JSONObject object = new JSONObject(map);
JsonObjectRequest request = new JsonObjectRequest(Request.Method.POST, path, object, new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
sendMsg(response.toString());
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
error.printStackTrace();
sendMsg(error.toString());
}
});
*/
queue.add(request);
}
private void sendMsg(String msg){
Message message = mHandler.obtainMessage();
message.obj = msg;
mHandler.sendMessage(message);
}
SSLContext getSSLContext(InputStream cer,InputStream bks){
try{
//初始化SSLContext
SSLContext context = SSLContext.getInstance("TLS");//TLS和SSL都可以
// 1.导入证书
Certificate certificate = CertificateFactory.getInstance("X.509")
.generateCertificate(cer);
// 2.证书导入密钥库
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null);
keyStore.setCertificateEntry("srca", certificate);
// 3.把密钥库放入信任管理器
TrustManagerFactory trustManagerFactory = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
// 4.生成信任管理器
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
//初始化keystore
KeyStore clientKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
clientKeyStore.load(bks, "123456".toCharArray());
//将keystore放入密钥管理器
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(clientKeyStore, "123456".toCharArray());
//生成密钥管理器
KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();
// 将信任管理器设置到SSLContext
context.init(keyManagers, trustManagers, new SecureRandom());
return context;
}catch(Exception e){
e.printStackTrace();
}
return null;
}
}
OkHttp双向证书验证的https请求: import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.HurlStack;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
public class MainActivity extends AppCompatActivity {
static Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
mTextView.setText(msg.obj.toString());
}
};
static String chen = "-----BEGIN CERTIFICATE-----\n" +
"MIIDWTCCAkGgAwIBAgIEcWnCMTANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJDTjENMAsGA1UE\n" +
"CBMEY2hlbjENMAsGA1UEBxMEY2hlbjENMAsGA1UEChMEY2hlbjENMAsGA1UECxMEY2hlbjESMBAG\n" +
"A1UEAxMJbG9jYWxob3N0MB4XDTE3MDIxMzE0MTIzNVoXDTI2MTIyMzE0MTIzNVowXTELMAkGA1UE\n" +
"BhMCQ04xDTALBgNVBAgTBGNoZW4xDTALBgNVBAcTBGNoZW4xDTALBgNVBAoTBGNoZW4xDTALBgNV\n" +
"BAsTBGNoZW4xEjAQBgNVBAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n" +
"ggEBAOCj9+qaE/DcDtJnEpeSc0+byTO3/yM673C4sgax7n4lCnjtmhgqiwASTCOnEMRJ6llmo/M8\n" +
"+msz9i+1vE4lte7AkZ/3Wfu04BXq9wmDlVNWU3kU6TfZMUhqifTvRC6zQmfJaBdS6SSfmBslrUUC\n" +
"ntD19vvGRLPkEt05s0itG54ex41fSgA4pBtj6qpBjLMS/03fCD6y3YdL+r0dN6bDxAuLo+2flJEy\n" +
"9CrnXEzLcZ172zD+5mfvhFI7F1fF1kdjT4pNi22sap5AOFZazaK7snq03cLTchC7yBwcPCJ6IqzY\n" +
"Yw6bVb79cj6nntbTb6lsrL7wv2kR8ubtiRTrrtCP2YMCAwEAAaMhMB8wHQYDVR0OBBYEFF5ZFY02\n" +
"FejgLSsO9DOZppwUhGS4MA0GCSqGSIb3DQEBCwUAA4IBAQCNg76X3tRCtnDi7cT5M8ADMzSUlYvA\n" +
"CaVYKQ+lB3WBLuqR3wVVJ/zeSGqiR4F59cj6Oij+fk5Fu05n+0nXX/sdirf2RTW1eaA+SzPYXdgA\n" +
"0u8XJdaPu58q0GCPFpUv24ljzQEr/hZBS9HWlHmkgByecpgrrToOc3jJNIQr8g1NVO/b8RCBFyx8\n" +
"Ax+Ytp8XNGKbmMnXifBxBnhMCT0DptmZuYsTacZ5qLqEhszChYSM3drYhoNId1HlLLeQbUumbB/8\n" +
"N1BVVH2LYPTJgKdXTQAzTWiUAss/HD78fe30qI3MDrZ1h4eF+vCHqOwAOiLxQ0Rpb5oMsVCblmoR\n" +
"+ool1ljG\n" +
"-----END CERTIFICATE-----";
private static TextView mTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.textview);
}
public void click(View view){
new Thread(){
@Override
public void run() {
super.run();
try {
okhttp();
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
}
void okhttp() throws Exception{
String path = "https://10.0.2.2:8444/OkHttp/text";
ByteArrayInputStream baos = new ByteArrayInputStream(chen.getBytes());
//InputStream iStream = new FileInputStream("chen_client.jks");
InputStream iStream = getAssets().open("chen_client.bks");
SSLManagerParams ssl = getSSLManagerParams(baos,iStream);
OkHttpClient client = new OkHttpClient.Builder()
.sslSocketFactory(ssl.mFactory,ssl.mTrustManager)
.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String s, SSLSession sslSession) {
return true;
}
})
.build();
//get
Request request = new Request.Builder().get().url(path).build();
//post
/*
Map<String,String> map = new HashMap<>();
map.put("userName", "183********");
map.put("password", "111111");
JSONObject jsonObject = new JSONObject(map);
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"),jsonObject.toString());
okhttp3.Request request = new okhttp3.Request.Builder().post(requestBody).url(path).build();
*/
Call call = client.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
sendMsg(e.toString());
}
@Override
public void onResponse(Call call, okhttp3.Response response) throws IOException {
sendMsg(response.body().string());
}
});
}
private void sendMsg(String msg){
Message message = mHandler.obtainMessage();
message.obj = msg;
mHandler.sendMessage(message);
}
static class SSLManagerParams{
public SSLSocketFactory mFactory;
public X509TrustManager mTrustManager;
}
SSLManagerParams getSSLManagerParams(InputStream cer,InputStream bks){
SSLManagerParams ssl = new SSLManagerParams();
try{
//初始化SSLContext
SSLContext context = SSLContext.getInstance("TLS");//TLS和SSL都可以
// 1.导入证书
Certificate certificate = CertificateFactory.getInstance("X.509")
.generateCertificate(cer);
// 2.证书导入密钥库
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null);
keyStore.setCertificateEntry("srca", certificate);
// 3.把密钥库放入信任管理器
TrustManagerFactory trustManagerFactory = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
// 4.生成信任管理器
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
//初始化keystore
KeyStore clientKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
clientKeyStore.load(bks, "123456".toCharArray());
//将keystore放入密钥管理器
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(clientKeyStore, "123456".toCharArray());
//生成密钥管理器
KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();
// 将信任管理器设置到SSLContext
context.init(keyManagers, trustManagers, new SecureRandom());
ssl.mFactory = context.getSocketFactory();
ssl.mTrustManager = chooseX509TrustManager(trustManagers);
return ssl;
}catch(Exception e){
e.printStackTrace();
}
return null;
}
private static X509TrustManager chooseX509TrustManager(TrustManager[] trustManagers)
{
for (TrustManager trustManager : trustManagers)
{
if (trustManager instanceof X509TrustManager)
{
return (X509TrustManager) trustManager;
}
}
return null;
}
}
好了,HPPTS全面解析到这里就结束了。以上的三种网络请求代码为了便于理解,并没有做合法性检测与封装,下面我提供了一个将三种https请求的简单封装工程。
参考:http://blog.csdn.net/lmj623565791/article/details/48129405