Https 协议
Https是在Http协议只上 加上了SSL
Http四次握手协议
1、客户端请求建立SSL链接,并向服务端发送一个随机数–Client random和客户端支持的加密方法,比如RSA公钥加密,此时是明文传输。
- 服务端回复一种客户端支持的加密方法、一个随机数–Server random、授信的服务器证书和非对称加密的公钥。
3.客户端收到服务端的回复后利用服务端的公钥,加上新的随机数–Premaster secret 通过服务端下发的公钥及加密方法进行加密,发送给服务器。
- 服务端收到客户端的回复,利用已知的加解密方式进行解密,同时利用Client random、Server random和Premaster secret通过一定的算法生成HTTP链接数据传输的对称加密key – session key。
X509TrustManager 自定义证书信任类:
1、Android 中的证书管理类 是X509TrustManager。
X509TrustManager是一个接口类,自定义证书管理类 需要实现X509TrustManager接口
public interface X509TrustManager extends TrustManager {
/*
*
*/
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException;
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException;
/**
返回受信任的X509证书数组。
*/
public X509Certificate[] getAcceptedIssuers();
}
该接口中只有三个方法:
-
checkClientTrusted()
该方法检查客户端的证书,若不信任该证书则抛出异常。由于我们不需要对客户端进行认证,因此我们只需要执行默认的信任管理器的这个方法。 -
checkServerTrusted
该方法检查服务器的证书,若不信任该证书同样抛出异常。通过自己实现该方法,可以使之信任我们指定的任何证书。在实现该方法时,也可以简单的不做任何处理,即一个空的函数体,由于不会抛出异常,它就会信任任何证书。 -
getAcceptedIssuers()
返回受信任的X509证书数组。
2、自定义X509TrustManager
自定义509TrustManager其核心方法为checkServerTrusted 指定信任哪些服务端证书
实现思路如下:
(1)实现一个默认的X509TrustManager,来校验标准的CA证书,若校验通过则return。
(2)若默认509TrustManager 校验CA证书失败。则尝试校验我们是不是我们内置的证书,若校验通过直接return,不抛异常。
(3) 以上两步均为通过,则抛异常,判定证书不合法。
public class MyX509TrustManager implements X509TrustManager {
private static final String TAG = "MyX509TrustManager";
/*
* The default X509TrustManager returned by SunX509. We'll delegate
* decisions to it, and fall back to the logic in this class if the
* default X509TrustManager doesn't trust it.
*/
private X509TrustManager sunJSSEX509TrustManager;
//自签名keystore
private KeyStore truststore;
private List<X509Certificate> x509caList = new ArrayList<X509Certificate>(1); //存储自签名的 X509证书列表
private List<InputStream> certificates;//自签名证书 输入流
public static MyX509TrustManager newInstance(List<InputStream> certificates) {
return new MyX509TrustManager(certificates);
}
private MyX509TrustManager(List<InputStream> certificates) {
this.certificates = certificates;
try {
// create a "default" JSSE X509TrustManager.
KeyStore ks = KeyStore.getInstance("JKS");
TrustManager[] tms = new TrustManager[0];
if (ks != null) {
FileInputStream is = null;
try {
is = new FileInputStream("trustedCerts");
ks.load(is, "passphrase".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509", "SunJSSE");
tmf.init(ks);
tms = tmf.getTrustManagers();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
LogUtil.e(TAG, e.getMessage(), e);
}
}
is = null;
}
} else {
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init((KeyStore) null);
tms = tmf.getTrustManagers();
}
/*
* Iterate over the returned trustmanagers, look
* for an instance of X509TrustManager. If found,
* use that as our "default" trust manager.
*/
for (int i = 0; i < tms.length; i++) {
if (tms[i] instanceof X509TrustManager) {
sunJSSEX509TrustManager = (X509TrustManager) tms[i];
break;
}
}
} catch (Exception e) {
try {
TrustManager[] tms = new TrustManager[0];
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init((KeyStore) null);
tms = tmf.getTrustManagers();
for (int i = 0; i < tms.length; i++) {
if (tms[i] instanceof X509TrustManager) {
sunJSSEX509TrustManager = (X509TrustManager) tms[i];
break;
}
}
} catch (Exception e1) {
LogUtil.e(TAG, "@@@Couldn't initialize https ca JSSE|" + e.getMessage(), e);
}
}
/**
* 自签名初始化
*/
this.truststore = createKeyStore(); //将自签名证书 加载KeyStore中
try {
Enumeration<String> aliasesIt = truststore.aliases();
if (aliasesIt != null) {
while (aliasesIt.hasMoreElements()) {
Certificate ca = truststore.getCertificate(aliasesIt.nextElement());
// Turn it to X509 format.
InputStream is = new ByteArrayInputStream(ca.getEncoded());
X509Certificate x509ca1 = (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(is);
x509caList.add(x509ca1);
//close input stream
closeIS(is);
}
}
} catch (Exception e) {
LogUtil.e(TAG, "@@@Couldn't initialize https ca custom|" + e.getMessage(), e);
}
}
/*
* Delegate to the default trust manager.
*/
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
/*
* Delegate to the default trust manager.
*/
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
//同时支持可信CA认证和自签名认证(任一种认证通过认为可信)
boolean ok = false;
//CA认证
if (sunJSSEX509TrustManager != null) {
try {
sunJSSEX509TrustManager.checkServerTrusted(chain, authType);
ok = true;
LogUtil.i(TAG, "@@@@@@@@@@@@@@@@@ ca checkServerTrusted success");
return;
} catch (CertificateException e) {
// do any special handling here, or rethrow exception.
ok = false;
}
}
//自签名认证
try {
for (X509Certificate cert : chain) {
for (X509Certificate ca : x509caList) {
try {
cert.verify(ca.getPublicKey());
ok = true;
LogUtil.i(TAG, "@@@@@@@@@@@@@@@@@ custom checkServerTrusted success");
return;
} catch (Exception e) {
ok = false;
}
}
}
} catch (Exception e) {
// do any special handling here, or rethrow exception.
ok = false;
}
if (!ok) {
LogUtil.i(TAG, "@@@@@@@@@@@@@@@@@ checkServerTrusted fails");
throw new CertificateException("https cert verify fails");
}
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return sunJSSEX509TrustManager.getAcceptedIssuers();
}
private static void closeIS(InputStream is) {
if (is != null) {
try {
is.close();
} catch (IOException e) {
LogUtil.e(TAG, e.getMessage(), e);
}
}
}
/**
* 得到HTTPS KeyStore
*
* @return
*/
private KeyStore createKeyStore() {
// https支持
try {
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
int index = 0;
if (certificates != null && !certificates.isEmpty()) {
for (InputStream is : certificates) {
try {
CertificateFactory cerFactory = CertificateFactory.getInstance("X509");
Certificate ca = cerFactory.generateCertificate(is);
String certificateAlias = Integer.toString(index++);
keyStore.setCertificateEntry(certificateAlias, ca);
} catch (Exception e) {
LogUtil.e(TAG, e.getMessage(), e);
} finally {
try {
if (is != null) {
is.close();
}
} catch (IOException e) {
LogUtil.e(TAG, e.getMessage(), e);
}
}
}
}
return keyStore;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
3、X509TrustManager的使用
//(1)创建SSLContext对象,并使用我们指定的信任管理器初始化
MyX509TrustManager trustManager = new MyX509TrustManager ()
TrustManager[] tm = {trustManager};
SSLContext sslContext = SSLContext.getInstance("SSL","SunJSSE");
sslContext.init(null, tm, new java.security.SecureRandom());
//(2)从上述SSLContext对象中得到SSLSocketFactory对象
SSLSocketFactory ssf = sslContext.getSocketFactory();
//(3) 设置OkhttpClient的sslSocketFactory
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(TimeOut, TimeUnit.SECONDS)
.readTimeout(TimeOut,TimeUnit.SECONDS)
.writeTimeout(TimeOut,TimeUnit.SECONDS)
.sslSocketFactory(ssf, trustManager)//https证书认证
.hostnameVerifier(new HttpsUtils.MyHostnameVerifier())//自定义了HostnameVerifier。在握手期间,如果 URL 的主机名和服务器的标识主机名不匹配,则验证机制可以回调此接口的实现程序来确定是否应该允许此连接。
.addInterceptor(MakeupInterceptor.newInstance())
.build();
Retrofit retrofit = new Retrofit.Builder()
.client(client)
.baseUrl(URL)
.addConverterFactory(ResponseConvertFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
retrofit.create(RequestService.class);
Chares 大花瓶 抓包原理
实际上 Chares 作为中间人代理,对客户端伪装服务器,通知对服务器伪装客户端。
- 截获真实客户端的HTTPS请求,伪装客户端向真实服务端发送HTTPS请求
- 接受真实服务器响应,用Charles自己的证书伪装服务端向真实客户端发送数据内容
关键的两点:
- 需要为手机设置代理,这样手机所有的请求都会路由到Chares
- 需要在手机端下载Chares自制的私有CA证书,并设置为信任证书。这样Chares可以伪装服务器 与客户端进行四次握手,建立https链接
参考链接:
https://www.zybuluo.com/Sweetfish/note/706401
https://www.jianshu.com/p/870451cb4eb0










网友评论