转载请注明出处:http://blog.csdn.net/huaiyiheyuan/article/details/53583253
一、https就是在http ,和tcp层之间添加了一层 ssl保护装置(个人理解)
1 、client给网站发送支持的算法
2、 网站选择算法 ,把包含公钥、网址的证书 发送给client ,
3、 client 验证证书 真伪、生成随机密码,用网站给的公钥加密发送
给网站
4、网站 hash认证 用对应的私钥解密,得到密码,给client回馈,握
手结束,用密码发送数据
这里面最重要的是客户端要认证服务器端的证书的有效性、
如果网站的证书没有经过认证(自己生成的证书),那么客户端就要验证证书
图形化表达 :http://www.ruanyifeng.com/blog/2011/08/what_is_a_digital_signature.html
二、Android Https请求
1、先找个现成的测试,卖火车票的,先去12306下载证书 http://www.12306.cn/mormhweb/ggxxfw/wbyyzj/201106/srca12306.zip (最好别安装到电脑原因点这里)
2、访问网站
1) 把下载的srca.cer放到assets目录下面,接下来就是搬代码了
https://developer.android.com/training/articles/security-ssl.html?hl=zh-cn
private void initCA() throws Exception {
// Load CAs from an InputStream
// could be from a resource or ByteArrayInputStream or ...)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = new BufferedInputStream(getAssets().open("srca.cer"));
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
} finally {
caInput.close();
}
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
}
2)用本地字符串代替证书
使用keytool工具到srca.cer目录下 : keytool -printcert -rfc -file srca.cer
*InputStream caInput = new BufferedInputStream(getAssets().open("srca.cer"));*
//替换成
InputStream caInput = new ByteArrayInputStream(String_CAs.getBytes());
注意 :
String_CAs = —–BEGIN CERTIFICATE—–
MIICmjCCAgOgAwIBA …
—–END CERTIFICATE—–
前后两个标签也需要
3) HttpsURLConnection请求数据
Executors.newCachedThreadPool().submit(new Runnable() {
@Override
public void run() {
try {
initCA();
String ur = "https://kyfw.12306.cn/otn/";
// String ur = "https://192.168.0.126:8443/img/pic1.jpg";
URL url = new URL(ur);
//打开该URL对应的资源的输入流
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.setSSLSocketFactory(sslContext.getSocketFactory());////前面initCA()方法就是为这里铺垫
// urlConnection.setHostnameVerifier(hostnameVerifier);
InputStream in = urlConnection.getInputStream();
BufferedReader bf = new BufferedReader(new InputStreamReader(in));
StringBuilder sb = new StringBuilder();
String s;
while ((s = bf.readLine()) != null) {
sb.append(s + "\n");
}
Message msg = Message.obtain();
msg.obj = sb;
handler.sendMessage(msg);
bf.close();
} catch (Exception e) {
e.printStackTrace();
}
}
});
三、配置子签名证书
上面是现成可以用的,我们开发者自己如何生成证书呢?
1、keytool生成证书
jon@jon-thinkpad:~/软件/server$ keytool -genkey -alias jon_server -keyalg RSA -keystore jon_server.jks -validity 3600 -storepass 123456
您的名字与姓氏是什么?
[Unknown]: zh 您的组织单位名称是什么? [Unknown]: z 您的组织名称是什么? [Unknown]: z 您所在的城市或区域名称是什么? [Unknown]: z 您所在的州或省份名称是什么? [Unknown]: z 该单位的两字母国家代码是什么 [Unknown]: cn CN=zh, OU=z, O=z, L=z, ST=z, C=cn 正确吗? [否]: 是 输入的主密码 (如果和 keystore 密码相同,按回车):
这样就生成了 jon_server.jks 密码都是123456(android的密钥也可以这样生成),接下来签发证书
~/软件/server$ keytool -export -alias jon_server -file jon_server.cer -keystore jon_server.jks -storepass 123456
生成的jon_server.cer
2、tomacat配置证书
1) 先下载tomcat(apache-tomcat-8.5.9.tar.gz我下的版本),到bin目录下运行startup.sh(linux环境),http://localhost:8080/测试下环境
2)打开config目录下的server.xml,在
节点内部(和Connector平行),添加
<Connector SSLEnabled="true" acceptCount="100" disableUploadTimeout="true" enableLookups="true" keystoreFile="/home/jon/软件/server/jon_server.jks" keystorePass="123456" maxSpareThreads="75" clientAuth="false" maxThreads="200" minSpareThreads="5" port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" scheme="https" secure="true" sslProtocol="TLS" />
keystoreFIle :jon_server.jks文件的绝对路径
3)启动tomcat,浏览器输入 https://localhost:8443/
看到这个页面
firfox添加例外
恭喜你配置OK
也可以在webapps 的 Root根目录下添加内容,我创建了img文件夹,里面添加了一些图片,然后访问 https://localhost:8443/img/pic1.jpg
4)客户端访问
这个配置和12306现成的证书读取配置是一样的,需要客户端和服务端在一个局域网内
initCA();
String ur = "https://192.168.1.125:8443/img/pic1.jpg";
URL url = new URL(ur);
//打开该URL对应的资源的输入流
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.setSSLSocketFactory(sslContext.getSocketFactory()); //前面initCA()方法就是为这里铺垫
urlConnection.setHostnameVerifier(hostnameVerifier); //域名验证
InputStream in = urlConnection.getInputStream();
BufferedReader bf = new BufferedReader(new InputStreamReader(in));
Bitmap bitmp = BitmapFactory.decodeStream(in);
Message msg = Message.obtain();
msg.obj = bitmp;
handler.sendMessage(msg);
bf.close();
HostnameVerifier hostnameVerifier = new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
// Open SSLSocket directly to gmail.com
return true;
}
};
三、https双向验证
1、SSL双向认证具体过程
① 浏览器发送一个连接请求给安全服务器。
② 服务器将自己的证书,以及同证书相关的信息发送给客户浏览器。
③ 客户浏览器检查服务器送过来的证书是否是由自己信赖的CA中心(如沃通CA)所签发的。如果是,就继续执行协议;如果不是,客户浏览器就给客户一个警告消息:警告客户这个证书不是可以信赖的,询问客户是否需要继续。
④ 接着客户浏览器比较证书里的消息,例如域名和公钥,与服务器刚刚发送的相关消息是否一致,如果是一致的,客户浏览器认可这个服务器的合法身份。
⑤ 服务器要求客户发送客户自己的证书。收到后,服务器验证客户的证书,如果没有通过验证,拒绝连接;如果通过验证,服务器获得用户的公钥。
⑥ 客户浏览器告诉服务器自己所能够支持的通讯对称密码方案。
⑦ 服务器从客户发送过来的密码方案中,选择一种加密程度最高的密码方案,用客户的公钥加过密后通知浏览器。
⑧ 浏览器针对这个密码方案,选择一个通话密钥,接着用服务器的公钥加过密后发送给服务器。
⑨ 服务器接收到浏览器送过来的消息,用自己的私钥解密,获得通话密钥。
⑩ 服务器、浏览器接下来的通讯都是用对称密码方案,对称密钥是加过密的。
双向认证则是需要服务端与客户端提供身份认证,只能是服务端允许的客户能去访问,安全性相对于要高一些。
2、配置tomcat
1)和上面一样生成客户端jon_client.jks文件,和CA
keytool -genkey -alias jon_client -keyalg RSA -keystore jon_client.jks -validity 3600 -storepass 123456
keytool -export -alias jon_client -file jon_client.cer -keystore jon_client.jks -storepass 123456
//为了让tomcat运行 还需要把cer添加到jks文件生成 jon_client_for_sever.jks
keytool -import -alias jon_client -file jon_client.cer -keystore jon_client_for_sever.jks
2)修改server.xml
在之前节点下 修改添加下面
clientAuth="true" truststoreFile ="/home/jon/软 件/server/jon_client_for_sever.jks"
把浏览器的例外清除重新来过 ,
在firfox输入 https://localhost:8443/ 然后添加例外,
接着就会看到这个界面
![这里写图片描述](https://img-blog.csdn.net/20161224194127300?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaHVhaXlpaGV5dWFu/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
3)配置客户端
sslContext.init(null, tmf.getTrustManagers(), null);//第一个参数提供客户端身份认证
/** * 双向认证 */
KeyStore clientKeyStore = KeyStore.getInstance(keyStoreType);
clientKeyStore.load(getAssets().open("jon_client.bks"), "123456".toCharArray());
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(clientKeyStore, "123456".toCharArray());
sslContext.init(keyManagerFactory.getKeyManagers(), tmf.getTrustManagers(), null);
正常情况应该在asset目录添加 jon_client.jks,但是android客户端不支持,用 portecle工具,把jks文件专程bks文件
然后跑起来就可以接受到数据了
代码 :https://github.com/BlogForMe/DrugStore
参考:
http://blog.csdn.net/lmj623565791/article/details/48129405
https://program-think.blogspot.com/2014/11/https-ssl-tls-1.html
http://www.cnblogs.com/P_Chou/archive/2010/12/27/https-ssl-certification.html