You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 22:15:02