如何在Swift中使用.crt和.key文件发送HTTPS请求
Swift 使用自定义 .crt/.key 证书发起 HTTPS 请求示例
首先需要先将你的 .crt 证书和 .key 私钥转换为 iOS 原生支持的 PKCS12(.p12)格式,你可以通过 openssl 命令完成转换:
openssl pkcs12 -export -out cert.p12 -inkey yourPrivateKey.key -in yourCertificate.crt
执行命令时会要求你设置导出密码,后续代码中需要用到该密码。转换完成后将 cert.p12 文件拖入 Xcode 项目,记得勾选对应 App target 的「Target Membership」选项。
完整实现代码
import Foundation import Security class CustomHTTPSClient: NSObject, URLSessionDelegate { static let shared = CustomHTTPSClient() private var session: URLSession! private override init() { super.init() let config = URLSessionConfiguration.ephemeral session = URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue()) } // 对外请求方法 func sendRequest(to url: URL, completion: @escaping (Data?, URLResponse?, Error?) -> Void) { let task = session.dataTask(with: url, completionHandler: completion) task.resume() } // 处理HTTPS身份验证代理 func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { // 处理客户端证书认证 if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate { guard let p12Path = Bundle.main.path(forResource: "cert", ofType: "p12") else { completionHandler(.cancelAuthenticationChallenge, nil) return } let p12Data = try! Data(contentsOf: URL(fileURLWithPath: p12Path)) // 生产环境请勿硬编码密码,建议存储到系统Keychain let p12Password = "你设置的p12导出密码" let options = [kSecImportExportPassphrase as String: p12Password] as CFDictionary var items: CFArray? let status = SecPKCS12Import(p12Data as CFData, options, &items) guard status == errSecSuccess, let itemsArr = items as? [[String: Any]], let identityDict = itemsArr.first, let identity = identityDict[kSecImportItemIdentity as String] as? SecIdentity else { completionHandler(.cancelAuthenticationChallenge, nil) return } let credential = URLCredential(identity: identity, certificates: nil, persistence: .forSession) completionHandler(.useCredential, credential) return } // 自签服务端证书校验逻辑,不需要可删除 if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust { guard let serverTrust = challenge.protectionSpace.serverTrust else { completionHandler(.cancelAuthenticationChallenge, nil) return } // 生产环境请不要直接信任,建议添加公钥比对等严格校验逻辑 let credential = URLCredential(trust: serverTrust) completionHandler(.useCredential, credential) return } completionHandler(.performDefaultHandling, nil) } } // 调用示例 // let testURL = URL(string: "你的HTTPS接口地址")! // CustomHTTPSClient.shared.sendRequest(to: testURL) { data, response, error in // if let error = error { // print("请求失败: \(error)") // return // } // if let data = data { // print("请求成功,返回数据长度: \(data.count)") // } // }
注意事项
- 生产环境不要将p12的导出密码硬编码在代码中,建议存储到系统Keychain中避免泄露
- 自签服务端证书的校验逻辑请不要直接信任所有证书,建议提前将服务端的证书公钥内置到App中,校验时比对公钥hash,避免中间人攻击
- 如果你遇到ATS(应用传输安全)拦截请求,可以在Info.plist中针对你的服务域名单独配置例外,不要全局关闭ATS安全策略
内容的提问来源于stack exchange,提问作者Benjamin Martin Leon
相关产品推荐
相关产品推荐

