Android App 如何防止抓包

xiangzhihong發表於2022-12-19

在軟體開發中,常用的抓包方式有 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 抓包問題。不過為了安全,很多的銀行類和支付類應用還會進行雙證書的校驗。

相關文章