在 Android 開發中,通過 OkHttp 自定義?SSLSocketFactory
?和?X509TrustManager
?可以有效增強 HTTPS 通信的安全性,防止中間人攻擊(如抓包工具 Charles/Fiddler 的攔截)。以下是實現防抓包的關鍵技術方案:
一、Okhttp設置固定證書(推薦)
OkHttp 內置了證書固定功能,無需自定義?SSLSocketFactory
,直接配置即可
val certificatePinner = CertificatePinner.Builder().add("example.com:443", "sha256/+o+LjQ5sWk3ABG4Gl7yZib6xTZ6F7OQ09qW7P9G+Z/Y=").build()httpClient.certificatePinner(certificatePinner)
1、example.com:?OpenSSL 要連接的?HTTPS 服務域名,你需要替換為實際的目標域名
2、443:?是 HTTPS 協議的默認端口號,若服務器 HTTPS 端口自己設置的,則需要修改
3、sha256/******:?OpenSSL 獲取到的證書
1、獲取證書(服務器證書的公鑰 SHA256 哈希值)
?在終端運行以下命令獲取證書
openssl s_client -connect example.com:443 | openssl x509 -pubkey | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
-
連接到服務器:
openssl s_client -connect example.com:443
?建立與目標服務器的 SSL 連接。注意??:example.com:443
?替換為你實際要連接的服務器地址和端口 -
提取證書:
openssl x509 -pubkey
?從連接中提取證書的公鑰部分。 -
轉換格式:
openssl pkey -pubin -outform der
?將公鑰轉換為 DER 格式(二進制)。 -
計算哈希:
openssl dgst -sha256 -binary
?計算 DER 格式公鑰的 SHA256 哈希。 -
Base64 編碼:
openssl enc -base64
?將二進制哈希值轉換為 Base64 字符串。
二、自定義 SSLSocketFactory + X509TrustManager
??????????如果需要更細粒度的控制(如僅信任特定證書)
1. 創建自定義 TrustManager
class CustomTrustManager : X509TrustManager {private val trustedCertificates by lazy { loadTrustedCertificates() }private fun loadTrustedCertificates(): List<X509Certificate> {// 從 assets 或 raw 目錄加載證書(如 .crt 或 .pem 文件)val inputStream = context.assets.open("certificate.crt")val certificateFactory = CertificateFactory.getInstance("X.509")return certificateFactory.generateCertificate(inputStream) as X509Certificate}override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String) {// 客戶端證書驗證throw CertificateException("Client certificates not supported!")}override fun checkServerTrusted(chain: Array<X509Certificate>, authType: String) {// 驗證服務器證書鏈是否與預置證書匹配if (!trustedCertificates.contains(chain[0])) {throw CertificateException("Untrusted server certificate!")}}override fun getAcceptedIssuers(): Array<X509Certificate> = arrayOf()
}
????2. 創建自定義 SSLSocketFactory???
class CustomSSLSocketFactory(private val trustManager: X509TrustManager) : SSLSocketFactory() {private val sslContext by lazy {SSLContext.getInstance("TLS").apply {init(null, arrayOf(trustManager), SecureRandom())}}override fun createSocket(s: Socket, host: String, port: Int, autoClose: Boolean): Socket {return sslContext.socketFactory.createSocket(s, host, port, autoClose)}// 其他重寫方法(直接委托給 sslContext.socketFactory)override fun getDefaultCipherSuites(): Array<String> {sslContext.socketFactory.defaultCipherSuites}override fun getSupportedCipherSuites(): Array<String> {sslContext.socketFactory.supportedCipherSuites}override fun createSocket(host: String, port: Int): Socket {sslContext.socketFactory.createSocket(host, port)}override fun createSocket(host: String, port: Int, localHost: InetAddress, localPort: Int): Socket {sslContext.socketFactory.createSocket(host, port, localHost, localPort)}override fun createSocket(address: InetAddress, port: Int): Socket {sslContext.socketFactory.createSocket(address, port)}override fun createSocket(address: InetAddress, port: Int, localAddress: InetAddress, localPort: Int): Socket {sslContext.socketFactory.createSocket(address, port, localAddress, localPort)}}
3. 配置 OkHttpClient
val trustManager = CustomTrustManager()val sslSocketFactory = CustomSSLSocketFactory(trustManager)val okHttpClient =OkHttpClient.Builder().sslSocketFactory(sslSocketFactory, trustManager).hostnameVerifier { hostname, session ->HttpsURLConnection.getDefaultHostnameVerifier().verify(hostname, session)}.build()