基础知识
感觉就是一堆有信誉的机构,说: 我们这些机构的公钥是可信的,我们下面的小弟当然也是可以信任的啦
然后大家就去当人家小弟,就是可信的了….
当然这里面有的大佬不高兴,就自己搞一套证书,比如12306
Https中,值得注意的密钥有:
- 服务器端的
公钥
和私钥
- 客户端的
随机密钥
值得注意的是一个HTTPS请求实际上就是两次HTTP传输.
1.客户端向服务器发起HTTPS请求,连接到服务器的443端口。
2.服务端收到请求,向客户端发送自己的公钥
3.客户端收到服务器公钥,开始验证证书的合法性,我们知道系统内置了一些证书,应该是叫顶级证书吧
我们的证书并不是啥大机构发的,肯定不在里面,那么就没法验证合法.
合法 > 继续
不合法 > 此次Https请求终止
4.客户端验证公钥合格后(也就是给你发消息的服务器是正经服务器),那么客户端会生成一个 随机密码,客户端会拿着这个随机密码和刚才收到的服务器密钥做非对称加密 >> 得到密文的密码
——–以上第一次http请求结束了——–
5.客户端会发起HTTPS中的第二个HTTP请求,发送客户端密钥(密文)给服务器。
6.服务器收到密文,会用自己的私钥对其进行非对称解密,得到客户端刚才生成的客户端随机密码.
此时服务器使用客户端随机密码,对数据进行对称加密
7.把对称加密后的数据返回给客户端,客户端对称解密,OK 此次Https完美结束
——–整个https请求结束了——–
其中 , 对称加密
和非对称加密
, 各司其职,共同完成整个请求.
对称加密: 最快速,最简单
非对称加密:速度慢,很安全,不需要把秘钥分发,客户端利用公钥加密的数据,只能是拥有秘钥的服务器解密
利用非对称加密的特性传递 客户端生成的随机密钥 ,达到只有服务器和客户端互相知道的密钥,从而使用密钥进行(高速简单的)对称加密数据.
第一部分:信任所有
这就是,我不管是谁传递的消息,不是你家服务器传递的消息,你也会信
Api.java (提供okhttp实例,并创建Retroit服务)
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
})
.sslSocketFactory(createSSLSocketFactory())
.build();
... ...
//这里是创建一个SSLSocketFactory,提供给上面的 .sslSocketFactory()
private SSLSocketFactory createSSLSocketFactory() {
SSLSocketFactory ssfFactory = null;
try {
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, new TrustManager[]{new TrustAllCerts()}, new SecureRandom());
ssfFactory = sc.getSocketFactory();
} catch (Exception e) {
}
return ssfFactory;
}
其中涉及到TrustAllCerts.java,可以看到只是实现X509TrustManager
,所有方法都是默认实现
/**
* If you have any questions, you can contact by email { wangzhumoo@gmail.com}
* @author 王诛魔 2018/1/8 下午2:25
*/
public class TrustAllCerts 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 new X509Certificate[0];
}
}
这里就以及可以了,信任所有的连接
第二部分:(强验证)
我只信任证书合法的服务器传递的数据.
- 查看Https的证书
在浏览器上看到这个,这个已经是我把证书添加为信任了,所以他是一个 安全
的标志
- 分析
这里是我查看当前网站证书的结构
最顶—是根证书,到期时间是2028年
最底—是我司证书,到期时间是2018.12.9日
这里我们可以发现,我们网站的证书是有时间限制的,那么就会有一个问题,到了2018.12.9这一天怎么办.
我也不知道会怎么样,应该是续签吧!那么万一这个证书变化了怎么办?
所以,我们应该把根证书置为信任.
- 下载保存
Mac的在 钥匙串访问 中
Windows 没法放图,在chrome上查看证书的时候应该就能保存.
HttpsUtils.java
/**
* If you have any questions, you can contact by email { wangzhumoo@gmail.com}
* @author 王诛魔 2018/1/10 下午5:07
* 支持https的工具类
*/
public class HttpsUtils {
private static final String TAG = "OkHttp";
/**
* 创建一个空白的KeyStore
* @return KeyStore
* @throws GeneralSecurityException
*/
private static KeyStore createEmptyKeyStore() throws GeneralSecurityException {
try {
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
//此处密码随意,不会产生问题
keystore.load(null, "password".toCharArray());
return keystore;
} catch (IOException e) {
return null;
}
}
/**
* TrustManager 生成
* @return
* @throws GeneralSecurityException
*/
private static TrustManager[] generateTrustManager() throws GeneralSecurityException {
//创建一个X.509格式的CertificateFactory
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
Certificate ca;
//证书工厂根据证书文件的流生成证书Certificate
InputStream assets = App.getContext().getResources().openRawResource(R.raw.rootca);
ca = certificateFactory.generateCertificate(assets);
Log.e(TAG, "trustManager: ca = " + ((X509Certificate) ca).getSubjectDN() );
//创建KeyStore,用来存储信任证书
KeyStore keyStor = createEmptyKeyStore();
keyStor.setCertificateEntry("ca",ca);
//创建一个默认类型的TrustManagerFactory
String defaultAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(defaultAlgorithm);
//用keyStore实例初始化TrustManagerFactory,此时TrustManagerFactory会信任我们保存的证书
tmf.init(keyStor);
//通过tmf获取TrustManager数组,TrustManager也会信任keyStor中的证书
return tmf.getTrustManagers();
}
/**
* 提供一个一个SSLSocketFactory
* @return SSLSocketFactory实例
*/
public static SSLSocketFactory generateSSLSocketFactory() {
try {
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, generateTrustManager(), new SecureRandom());
Log.e(TAG, "generateSSLSocketFactory ");
return sc.getSocketFactory();
} catch (GeneralSecurityException e) {
return null;
}
}
}
注释很清楚了.
关键:
1.拿到帧数的流
InputStream assets = App.getContext().getResources().openRawResource(R.raw.rootca);
2.保存到keystore
KeyStore keyStor = createEmptyKeyStore();
keyStor.setCertificateEntry("ca",ca);
3.初始化并拿到TrustManager[]
tmf.init(keyStor);
tmf.getTrustManagers()
使用即可:
//这样就Ok
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.hostnameVerifier((hostname, session) -> true)
.sslSocketFactory(HttpsUtils.generateSSLSocketFactory())
.build();