• JKS:数字证书库。JKS里有KeyEntry和CertEntry,在库里的每个Entry都是靠别名(alias)来识别的。
  • P12:是PKCS12的缩写。同样是一个存储私钥的证书库,由.jks文件导出的,用户在PC平台安装,用于标示用户的身份。
  • CER:俗称数字证书,目的就是用于存储公钥证书,任何人都可以获取这个文件 。
  • BKS:Android平台专用证书库格式。

crt转bks

下载Bouncy Castle,将该文件放到Java\jdk1.8.0_20\jre\lib\ext目录下,或者使用-providerpath指定路径。
http://www.bouncycastle.org/latest_releases.html

keytool -importcert -v -trustcacerts -alias mykey -file githubcom.crt -keystore keystore.bks -storetype BKS -providerclass org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath bcprov-jdk15on-1.47.jar -storepass testing

单向认证

SSL Pinning

在客户端预置服务器公钥证书或者指纹,在和HTTPS请求获取的服务器证书做对比的方式。

双向验证

什么是双向认证?举个栗子。

土匪:蘑菇,你哪路?什么价?(什么人?到哪里去?)
杨子荣:哈!想啥来啥,想吃奶来了妈妈,想娘家的人,孩子他舅舅来了。(找同行)
杨子荣:拜见三爷!
土匪:天王盖地虎!(你好大的胆!敢来气你的祖宗?)
杨子荣:宝塔镇河妖!(要是那样,叫我从山上摔死,掉河里淹死。)

简单来说,当两个互不认识的人交易的时候,在A说出口令之后,B能说出只有A和B知道的口令。

生成证书

1) 生成客户端keystore

keytool -genkeypair -alias client -keyalg RSA -validity 3650 -keypass 123456 -storepass 123456 -keystore client.jks

2) 生成服务端keystore

keytool -genkeypair -alias server -keyalg RSA -validity 3650 -keypass 123456 -storepass 123456 -keystore server.keystore

注意:CN必须与IP地址匹配,否则需要修改host

3) 导出客户端证书

keytool -export -alias client -file client.cer -keystore client.jks -storepass 123456

4) 导出服务端证书

keytool -export -alias server -file server.cer -keystore server.keystore -storepass 123456

5) 证书交换

将客户端证书导入服务端keystore中,再将服务端证书导入客户端keystore中,一个keystore可以导入多个证书,生成证书列表。

生成客户端信任证书库(由服务端证书生成的证书库):
keytool -import -v -alias server -file server.cer -keystore truststore.jks -storepass 123456

将客户端证书导入到服务器证书库(使得服务器信任客户端证书):
keytool -import -v -alias client -file client.cer -keystore server.keystore -storepass 123456

6) 生成Android识别的BKS库文件

使用portecle将client.jks和truststore.jks转换成bks格式,放到android客户端的assert目录下。

配置tomcat

修改server.xml文件,配置8443端口

1
2
3
4
5
<Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol"
maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
clientAuth="true" sslProtocol="TLS"
keystoreFile="${catalina.base}\conf\server.keystore" keystorePass="123456"
truststoreFile="${catalina.base}\conf\server.keystore" truststorePass="123456" />

由于没有客户端证书,浏览器访问将被拒绝。

安卓客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
try {
// 服务器端需要验证的客户端证书,其实就是客户端的keystore
KeyStore keyStore = KeyStore.getInstance("BKS");
// 客户端信任的服务器端证书
KeyStore trustStore = KeyStore.getInstance("BKS");
//读取证书
InputStream ksIn = getResources().getAssets().open("client.bks");
InputStream tsIn = getResources().getAssets().open("truststore.bks");
//加载证书
keyStore.load(ksIn,"123456".toCharArray());
trustStore.load(tsIn,"123456".toCharArray());
IOUtils.close(ksIn);
IOUtils.close(tsIn);
//初始化SSLContext
SSLContext sslContext = SSLContext.getInstance("TLS");
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("X509");
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("X509");
trustManagerFactory.init(trustStore);
keyManagerFactory.init(keyStore, "123456".toCharArray());
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
//通过HttpsURLConnection设置链接
SSLSocketFactory socketFactory = sslContext.getSocketFactory();
HttpsURLConnection.setDefaultSSLSocketFactory(socketFactory);
URL url = new URL(url);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
//设置ip授权认证:如果已经安装该证书,可以不设置,否则需要设置
conn.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
InputStream inputStream = conn.getInputStream();
String content = getString(inputStream);
IOUtils.close(inputStream);
System.out.println(content);
} catch (Exception e) {
e.printStackTrace();
}

Burp 代理

提取app中的客户端证书,在Burp的Project options -> SSL选项卡Client SSL Certificates栏处导入,之后Burp便可直接访问目标站点。

app客户端依旧使用Xposed JustTrustMe插件绕过服务器证书校验。