这篇文章谈谈如何防止 App 被抓包
首先我们要知道常用的抓包方式有 Charles 和 Fiddler。他们通过在手机网络中添加代理的方式,拿到 App 的请求。
如果是 Https 连接的话,我们要先在手机中添加 Charles或Fiddler 的证书,然后Charles通过修改服务器发送证书链,让手机信任Charles 的证书,从而拿到 App 的请求。
下面是一些对策:
一、使用无代理 Proxy.NO_PROXY
charles 和 fiddler 都使用代理来进行抓包,对网络客户端使用无代理模式即可防止抓包,如
OkHttpClient.Builder()
.retryOnConnectionFailure(true)
.proxy(Proxy.NO_PROXY)
.sslSocketFactory(ssl, trustManager)
.build()
通常情况下上述的办法有用,但是无法防住使用 VPN 导流进行的抓包( Drony + Charles)
使用VPN抓包的原理是,先将手机请求导到VPN,再对VPN的网络进行Charles的代理,绕过了对App的代理。
下面是对策:
二、使用证书校验
这种方式要在app嵌入证书,以okhttp为例:
当okhttp使用X509TrustManager对服务器证书进行校验时,如果服务器证书的 subjectDN 和嵌入证书的 subjectDN 一致,我们再进行签名内容 signature 的比对,如果不一致,抛出异常。示例代码如下:
- 首先从本地读出证书,获取一个X509Certificate
val myCrt: X509Certificate by lazy {
getCrt(R.raw.my_ca)
}
private fun getCrt(@RawRes raw: Int): X509Certificate {
val certificateFactory = CertificateFactory.getInstance("X.509")
val input = ApplicationContext.resources.openRawResource(raw)
input.use {
return certificateFactory.generateCertificate(input) as X509Certificate
}
}
- 检查服务器证书时对比嵌入的证书
private fun getTrustManagerInRelease(): X509TrustManager {
return object : X509TrustManager {
override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String?) {}
override fun getAcceptedIssuers(): Array<X509Certificate> = arrayOf()
override fun checkServerTrusted(chain: Array<X509Certificate>, authType: String?) {
val myCrt: X509Certificate = myCrt
if (chain[0].subjectDN.name == myCrt.subjectDN.name) {
if (!myCrt.signature!!.contentEquals(chain[0].signature)) {
throw SSLHandshakeException("签名不符!")
}
}
}
}
}
- 将自定义的 SSLSocketFactory 和 X509TrustManager 将入到 okhttp 客户端
private fun getClient(ssl: SSLSocketFactory, trustManager: X509TrustManager): OkHttpClient {
return OkHttpClient.Builder()
.retryOnConnectionFailure(true)
.proxy(Proxy.NO_PROXY)
.sslSocketFactory(ssl, trustManager)
.build()
}
这样一来便无法通过 Drony + Charles 进行抓包了