在軟體開發中,常用的抓包方式有 Charles 、 Fiddler和Burp,它們透過在手機網路中新增代理的方式,然後安裝信任證書,接著就可以在 App 請求的時候拿到請求資料。不過,這也可能導致一些安全問題,所以對於我們通常的處理方式是,對於線上執行的包,需要防止這些抓包手段。
1,使用無代理 Proxy.NO_PROXY
在Android開發中,大部分的App的網路請求都是基於charles 和 fiddler 來進行抓包的,對網路客戶端使用無代理模式即可防止抓包,程式碼如下。
OkHttpClient.Builder()
.retryOnConnectionFailure(true)
.proxy(Proxy.NO_PROXY)
.sslSocketFactory(ssl, trustManager)
.build()
通常情況下上述的辦法有用,但是無法防住使用 VPN 導流進行的抓包( Drony + Charles),使用VPN抓包的原理是,先將手機請求導到VPN,再對VPN的網路進行Charles的代理,繞過了對App的代理。
2,使用證書校驗
此種方式可以有效的防止抓包,需要在App端嵌入證書,下面是證書校驗的一些說明:
下面是使用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 抓包問題。不過為了安全,很多的銀行類和支付類應用還會進行雙證書的校驗。