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

Swift开发:如何在不开启NSAllowArbitraryLoads的情况下处理自签名证书?

处理Swift中自签名证书的服务器认证挑战

嘿,作为Swift新手碰到自签名证书的认证问题太正常了——毕竟测试服务器用自签名证书是常事,但系统默认会拒绝这种“不受信任”的证书,所以咱们得在URLSession的认证挑战方法里手动处理。

先给你补全并优化你的didReceive challenge方法,同时拆解每一步的逻辑:

func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
    // 只处理服务器信任类型的认证挑战
    guard challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust else {
        // 其他类型的挑战(比如HTTP Basic认证),直接用默认处理逻辑
        completionHandler(.performDefaultHandling, nil)
        return
    }
    
    // 仅在开发测试环境下使用!生产环境绝对不能这么做!
    #if DEBUG
        // 获取服务器的信任对象
        guard let serverTrust = challenge.protectionSpace.serverTrust else {
            completionHandler(.cancelAuthenticationChallenge, nil)
            return
        }
        
        // 创建信任该服务器的凭据
        let credential = URLCredential(trust: serverTrust)
        
        // 告诉会话接受这个凭据,继续请求
        completionHandler(.useCredential, credential)
    #else
        // 生产环境直接用默认逻辑,拒绝自签名证书
        completionHandler(.performDefaultHandling, nil)
    #endif
}

关键注意事项:

  • 绝对不要在生产环境用这段代码:上面用了#if DEBUG宏,确保只有在开发测试时才跳过证书验证,生产环境会走系统默认的安全逻辑,避免安全风险。
  • 如果想让测试环境更安全(比如防止连错测试服务器),可以额外验证证书的指纹:
    1. 导出测试服务器的自签名证书,计算它的SHA256指纹
    2. 在代码里把预设的指纹和服务器返回证书的指纹对比,只有匹配才信任

举个指纹验证的简化示例:

// 预设测试服务器证书的SHA256指纹(示例值,替换成你自己的)
let allowedFingerprint = "ABC123DEF456GHI789JKL012MNO345PQR678STU901VWX234YZ567"

func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
    guard challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust,
          let serverTrust = challenge.protectionSpace.serverTrust,
          let certificate = SecTrustGetCertificateAtIndex(serverTrust, 0) else {
        completionHandler(.performDefaultHandling, nil)
        return
    }
    
    #if DEBUG
        // 获取证书的data
        let certificateData = SecCertificateCopyData(certificate) as Data
        // 计算SHA256指纹
        let sha256 = certificateData.sha256()
        let fingerprint = sha256.map { String(format: "%02x", $0) }.joined().uppercased()
        
        if fingerprint == allowedFingerprint {
            let credential = URLCredential(trust: serverTrust)
            completionHandler(.useCredential, credential)
        } else {
            // 指纹不匹配,拒绝连接
            completionHandler(.cancelAuthenticationChallenge, nil)
        }
    #else
        completionHandler(.performDefaultHandling, nil)
    #endif
}

// 给Data加个计算SHA256的扩展
extension Data {
    func sha256() -> Data {
        var hash = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
        self.withUnsafeBytes {
            _ = CC_SHA256($0.baseAddress, CC_LONG(self.count), &hash)
        }
        return Data(hash)
    }
}

这样既解决了测试环境的认证问题,又比直接信任所有服务器更安全。

内容的提问来源于stack exchange,提问作者Kevin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:39:14