在使用 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 是最常用的解决方案。