IOS开发SSL-Pining

SSL

  • SSL(Secure Sockets Layer,安全套接层)是一种安全协议,用于在互联网上建立加密链接,确保数据在客户端和服务器之间安全传输。SSL 通过使用加密算法来保护数据不被未授权访问、篡改或拦截。

SSL链接步骤:

  • Client hello:浏览器会将"支持的加密组件"/"尝试连接到Host头"等信息发送给服务器, 并会附上一份随机生成的 session ticket1。

  • Sever hello:服务器收到浏览器发送来的 TLS 握手请求后, 存储浏览器发送的session ticket1, 然后根据发送来的 host 寻找对应的的服务器证书, 然后会将服务器证书, 服务器与浏览器妥协(均支持)的加密套件方法, 和一份随机生成的 session ticket2返回给浏览器.

  • Cipher spec:浏览器收到服务器返回的证书后, 会验证证书有效性。验证步骤大概如下:

    • 验证证书有效期

    • 验证证书域名

    • 验证证书吊销状态

    • 验证证书颁发机构, 如果颁发机构是中间证书, 在验证中间证书的有效期/颁发机构/吊销状态。一直验证到最后一层证书, 如果最后一层证书是在操作系统或浏览器内置, 那么就是可信的, 否则就是自签名

  • 若检查通过, 随机生成一份 session ticket 3 (这是浏览器生成的第二份 ticket), 通过返回证书中的公钥, 用协商的"秘钥交换算法"加密, 返回给服务器。

  • 浏览器和服务器用交换得到的密钥进行传输,对称加密算法。

  • session ticket3是无法窃取的

    • 攻击者在客户端和服务器建立中间代理,将两头的证书替换为自己的证书,但攻击者的证书不在信任列表中,因此两头都会警告。

SSL-Pinning

  • 证书锁定(SSL/TLS Pinning)顾名思义,将服务器提供的SSL/TLS证书内置到移动端开发的APP客户端中,当客户端发起请求时,通过比对内置的证书和服务器端证书的内容,以确定这个连接的合法性

  • 简单来说就是,在app代码指定证书/公钥,保证客户端和服务端的通信安全性和唯一性。但需要考虑有证书效期的问题。证书和公钥都是用摘要生成hash值

    • 证书锁定

      import Foundation
      
      // 1. 准备证书文件,确保服务器证书在项目中可用
      guard let serverCertificateURL = Bundle.main.url(forResource: "serverCertificate", withExtension: "der") else {
          fatalError("缺少服务器证书文件")
      }
      
      do {
          // 2. 从项目中读取证书文件
          let serverCertificateData = try Data(contentsOf: serverCertificateURL)
          let serverCertificate = SecCertificateCreateWithData(nil, serverCertificateData as CFData)
      
          // 3. 创建服务器信任策略
          let serverTrustPolicy = ServerTrustPolicy.pinCertificates(certificates: [serverCertificate], validateCertificateChain: true, validateHost: true)
      
          // 4. 配置 URLSession
          let configuration = URLSessionConfiguration.default
          configuration.serverTrustPolicy = serverTrustPolicy
      
          // 5. 创建 URLSession 对象
          let session = URLSession(configuration: configuration)
      
          // 6. 发起网络请求
          if let url = URL(string: "https://example.com") {
              let task = session.dataTask(with: url) { data, response, error in
                  // 处理响应
              }
              task.resume()
          }
      } catch {
          print("证书读取失败: \(error)")
      }
    • 公钥锁定:避免证书过期

  • 公钥锁定:

    /// 对比服务器的公钥是不是官方公钥(青藤长连域名认为是官方链接)
    for serverPublicKey in trust.publicKeys {
        for pinnedPublicKey in keys where pinnedPublicKey == serverPublicKey {
            security.evaluateTrust(trust: trust, domain: domain, completion: completion)
            return
        }
    }
    
    /// 证书不匹配直接中断连接,同时上报错误日志给服务器
    let error = CFErrorCreate(kCFAllocatorDefault, "证书单向校验失败" as NSString?, ResponseErrorCode.unknown.rawValue, nil)
    QTLogError(.webSocket, "\(String(describing: error))")
    completion(.failed(error))

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值