简介
众所周知,我们在做手机端开发的时候,网络访问如果不做加密的话,请求数据很容易被抓包工具获取,从而造成安全隐患。所以我们怎么避免数据被别人通过抓包工具抓取呢?
SSL Pinning不是一个新概念,尽管很多开发者使用SSL来保证数据传输的安全性,但基本上都是未设置受信任证书,所以无法防止中间人攻击,数据还是可以被抓包。
证书锁定(SSL/TLS Pinning)顾名思义,将服务器提供的SSL/TLS证书内置到移动端开发的APP客户端中,当客户端发起请求时,通过比对内置的证书和服务器端证书的内容,以确定这个连接的合法性。
方法一
获取服务器证书摘要
创建一个脚本文件,certs.sh,文件内容如下:
1 2 3 4 5 6 7 8 9 10 11 12
| #!/bin/bash certs=`openssl s_client -servername $1 -host $1 -port 443 -showcerts </dev/null 2>/dev/null | sed -n '/Certificate chain/,/Server certificate/p'` rest=$certs while [[ "$rest" =~ '-----BEGIN CERTIFICATE-----' ]] do cert="${rest%%-----END CERTIFICATE-----*}-----END CERTIFICATE-----" rest=${rest#*-----END CERTIFICATE-----} echo `echo "$cert" | grep 's:' | sed 's/.*s:\(.*\)/\1/'` echo "$cert" | openssl x509 -pubkey -noout | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -binary | openssl enc -base64 done
|
使用方法如下,可以看到获取的证书摘要信息:
1 2 3 4 5 6
| # ./certs.sh www.jllydj.gov.cn
/CN=www.jllydj.gov.cn 2o2MOiraYxPymc3kSEYyLx8IbdlToM0D5Je9PK/lSlk= /C=US/O=DigiCert Inc/OU=www.digicert.com/CN=Encryption Everywhere DV TLS CA - G1 GI75anSEdkuHj05mreE0Sd9jE6dVqUIzzXRHHlZBVbI=
|
通过okhttp设置CertificatePinner
1 2 3 4 5 6 7
| CertificatePinner certPinner = new CertificatePinner.Builder() .add("www.jllydj.gov.cn", "sha256/2o2MOiraYxPymc3kSEYyLx8IbdlToM0D5Je9PK/lSlk=") .add("www.jllydj.gov.cn", "sha256/GI75anSEdkuHj05mreE0Sd9jE6dVqUIzzXRHHlZBVbI=") .build(); builder.certificatePinner(certPinner);
|
方法二
Android okHttp 如何实现SSL Pinning
1 2 3 4
| CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
InputStream caInput = getResources().openRawResource(R.raw.ca); Certificate ca = certificateFactory.generateCertificate(caInput);
|
- 通过Ca创建一个包含可信任证书的keystore文件
1 2 3 4
| String keyStoreType = KeyStore.getDefaultType(); KeyStore keyStore = KeyStore.getInstance(keyStoreType); keyStore.load(null, null); keyStore.setCertificateEntry("ca", ca);
|
- Create a custom TrustManager from the trusted CAs in the keystore
1 2 3
| String algorithm = TrustManagerFactory.getDefaultAlgorithm(); TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(algorithm); trustManagerFactory.init(keyStore);
|
1 2 3 4 5 6 7 8 9 10 11 12
| // Install the all-trusting trust manager final SSLContext sslContext = SSLContext.getInstance("SSL"); sslContext.init(null, trustManagerFactory.getTrustManagers(), null); // Create an ssl socket factory with our all-trusting manager final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustManagerFactory.getTrustManagers()[0]); builder.hostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String hostname, SSLSession session) { return true; } });
|
这样就完成了android客户端的SSL PINning设置。
问题
常用SSLpinning绕过方法以及原理介绍
在前面我们已经介绍了SSL pinning的原理以及具体的实现,那么我们想要绕过SSL pinning的话,只需要将证书校验的过程绕过就可以。那么我们可以通过hook的方式来修改证书校验过程,这样就能成功的绕过SSL pinning了。
本人常用且比较熟悉的hook工具有两种,分别是frida和Xposed,这两种工具中都有hook所有https证书校验方法的模块。
其中我使用的比较多的是基于Xposed框架下的Justtrustme模块。该模块对上述所说的https实现证书校验的过程都添加了hook代码,至于具体代码细节我这里就不详细说明了,感兴趣的话可以自己去查看源码
也可以使用国内大神写的太极框架,太极 阳是不需要root的,太极 magic是需要root的。太极框架兼容Xposed框架。https://www.taichi-app.com/#/index
参考资料