在使用 Alamofire 的 Session
實現無證書訪問 HTTPS 接口時,如果要求抓包不是明文(即防止中間人攻擊和抓包工具如 Charles/Fiddler 解密 HTTPS 流量),可以通過以下方式實現:
1. 使用 SSL Pinning(證書綁定)
SSL Pinning 是一種防止中間人攻擊的技術,通過將服務器的公鑰或證書嵌入客戶端,確保客戶端只與特定的服務器通信。
實現步驟:
獲取服務器的證書
從服務器獲取.cer
或.der
格式的證書文件,并將其添加到 Xcode 項目中。-
配置 Alamofire 的
ServerTrustManager
和ServerTrustEvaluating
使用 Alamofire 的ServerTrustManager
和ServerTrustEvaluating
來實現 SSL Pinning。import Alamofire // 1. 加載證書 let certificatePath = Bundle.main.path(forResource: "your_certificate", ofType: "cer")! let certificateData = try! Data(contentsOf: URL(fileURLWithPath: certificatePath)) // 2. 創建 ServerTrustEvaluating let evaluator = PinnedCertificatesTrustEvaluator(certificates: [certificateData]) // 3. 配置 ServerTrustManager let serverTrustManager = ServerTrustManager(evaluators: ["yourserver.com": evaluator]) // 4. 創建 Session let session = Session(serverTrustManager: serverTrustManager) // 5. 發起請求 session.request("https://yourserver.com/api").response { response in debugPrint(response) }
效果
抓包工具(如 Charles)將無法解密 HTTPS 流量,因為客戶端只信任綁定的證書。
2. 禁用明文傳輸(防止 HTTP 請求)
確保應用只使用 HTTPS,禁用 HTTP 請求。
實現步驟:
在 Info.plist
中添加以下配置:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<false/>
<key>NSExceptionDomains</key>
<dict>
<key>yourserver.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<false/>
<key>NSExceptionRequiresForwardSecrecy</key>
<true/>
</dict>
</dict>
</dict>
3. 使用自定義的 URLSessionDelegate
如果需要更細粒度的控制,可以實現 URLSessionDelegate
的 urlSession(_:didReceive:completionHandler:)
方法,手動驗證服務器證書。
實現步驟:
import Alamofire
class CustomSessionDelegate: SessionDelegate {
override func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
// 驗證服務器證書
if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
if let serverTrust = challenge.protectionSpace.serverTrust {
// 自定義驗證邏輯
let credential = URLCredential(trust: serverTrust)
completionHandler(.useCredential, credential)
return
}
}
completionHandler(.performDefaultHandling, nil)
}
}
// 創建自定義 Session
let session = Session(delegate: CustomSessionDelegate())
// 發起請求
session.request("https://yourserver.com/api").response { response in
debugPrint(response)
}
4. 防止抓包工具注入證書
抓包工具(如 Charles)通常會要求用戶安裝自定義根證書來解密 HTTPS 流量。可以通過以下方式防止抓包工具注入證書:
實現步驟:
-
檢測設備是否安裝了抓包工具的證書
檢查設備是否安裝了 Charles/Fiddler 等工具的根證書。func isProxyEnabled() -> Bool { if let proxySettings = CFNetworkCopySystemProxySettings()?.takeRetainedValue() as? [String: Any], let httpProxy = proxySettings["HTTPProxy"] as? String, !httpProxy.isEmpty { return true } return false }
拒絕請求或提示用戶
如果檢測到抓包工具,可以拒絕請求或提示用戶關閉代理。
5. 使用雙向 TLS(mTLS)
雙向 TLS(mTLS)要求客戶端和服務器都提供證書,進一步增加安全性。
實現步驟:
獲取客戶端證書
從服務器獲取客戶端證書(.p12
文件)。-
加載客戶端證書
在代碼中加載客戶端證書并配置 Alamofire。import Alamofire // 1. 加載客戶端證書 let certificatePath = Bundle.main.path(forResource: "client_certificate", ofType: "p12")! let certificateData = try! Data(contentsOf: URL(fileURLWithPath: certificatePath)) // 2. 創建 URLCredential let credential = URLCredential(pkcs12: certificateData, password: "your_password") // 3. 創建 Session let session = Session() // 4. 發起請求 session.request("https://yourserver.com/api") .authenticate(with: credential) .response { response in debugPrint(response) }
6. 總結
- SSL Pinning 是最常用的防止抓包工具解密 HTTPS 流量的方法。
- 禁用明文傳輸 確保應用只使用 HTTPS。
-
自定義
URLSessionDelegate
提供更細粒度的控制。 - 檢測抓包工具 可以防止用戶使用抓包工具。
- 雙向 TLS 提供更高的安全性,但實現復雜度較高。
根據你的需求選擇合適的方法,通常 SSL Pinning 是最常用的解決方案。