15-3.【HTTP】TLS/SSL 握手过程是怎样的?在 iOS 中如何验证服务器证书?

5 阅读2分钟

1. TLS 1.2 握手过程 (经典四次握手)

在握手完成前,所有的通信都是明文的;握手完成后,所有的通信都是加密的。

  1. Client Hello: 客户端(iOS App)发送自己支持的 TLS 版本、加密算法列表(Cipher Suites)和一个随机数 R1R_1

  2. Server Hello & Certificate:

    • 服务器选择一套加密算法。
    • 发送服务器的 数字证书(包含服务器公钥)。
    • 发送另一个随机数 R2R_2
  3. Certificate Verification & Key Exchange:

    • 客户端验证证书合法性(颁发机构、有效期、域名)。
    • 客户端生成第三个随机数(Pre-master Secret) ,并用证书里的服务器公钥加密发送给服务器。
  4. Finish:

    • 双方根据 R1,R2R_1, R_2 和 Pre-master Secret 计算出最终的对称密钥(Session Key)
    • 双方发送“Finished”消息,确认握手完成,后续数据全部用该对称密钥加密。

2. 在 iOS 中如何验证服务器证书?

在 iOS 开发中,验证过程通常分为两个层面:系统默认验证自定义验证(如 SSL Pinning)

A. 系统默认验证 (ATS)

自 iOS 9 起,Apple 引入了 App Transport Security (ATS) 。只要你使用 URLSession 请求 https:// 开头的地址,系统会自动帮你完成以下工作:

  • 检查证书链是否完整。
  • 检查证书是否由受信任的根证书颁发机构(CA)签名。
  • 检查域名是否与证书匹配。

B. 自定义验证(处理自签名证书或 SSL Pinning)

如果你使用的是公司内部的自签名证书,或者为了极高安全性防止中间人攻击而使用 SSL Pinning(证书固定) ,你需要实现 URLSessionDelegate

代码示例:实现证书校验回调

Swift

extension NetworkManager: URLSessionDelegate {
    func urlSession(_ session: URLSession, 
                    didReceive challenge: URLAuthenticationChallenge, 
                    completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
        
        // 1. 判断是否是服务器信任挑战
        guard challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust,
              let serverTrust = challenge.protectionSpace.serverTrust else {
            completionHandler(.performDefaultHandling, nil)
            return
        }

        // 2. 如果是 SSL Pinning,这里需要对比本地预埋的证书
        // let remoteCertificate = SecTrustGetCertificateAtIndex(serverTrust, 0)
        // let localCertificateData = ... 从 App Bundle 读取的 .cer 文件
        
        // 3. 校验逻辑
        if customVerify(serverTrust) {
            completionHandler(.useCredential, URLCredential(trust: serverTrust))
        } else {
            // 校验失败,断开连接
            completionHandler(.cancelAuthenticationChallenge, nil)
        }
    }
}

3. 什么是 SSL Pinning (证书固定)?

虽然 HTTPS 很安全,但如果用户的手机被安装了恶意的“根证书”(例如抓包工具 Charles 的证书),中间人依然可以解密你的流量。

SSL Pinning 的逻辑是:

在 App 内部打包一份服务器的公钥或证书文件。握手时,App 不再仅仅信任系统信任库,而是直接对比服务器发来的证书和本地预埋的是否一致。

  • 优点:极大提升安全性,防抓包。
  • 缺点:维护成本高。如果服务器证书更换了,App 必须强制更新,否则网络请求会全部失败。