在启用ATS并绑定了自己的根CA的情况下,无法在iOS应用程序中通过HTTPS进行通信

kkih6yb8  于 2023-06-07  发布在  iOS
关注(0)|答案(1)|浏览(177)

我们正在尝试制作一个应用程序,该应用程序将使用NSURLSession通过HTTPS与我们的多个服务器进行通信,因为我们正在使用我们自己的根CA,该根CA捆绑在我们的应用程序中,并且ATS完全启用(NSAllowsArbitraryLoads设置为False)。
在调用NSURLSession Authentication委托(即“URLAuthenicationChallenge”)时,我们通过“SecTrustSetAnchorCertificates”设置锚证书,该证书通过验证其签名加上其证书链中的证书签名来验证证书,直到锚证书。还使用SecTrustSetAnchorCertificatesOnly排除其他锚点。
成功执行SecTrustEvaluate后,在SessionDataTask completionHandler中收到错误,如下所述:

[4704:1445043] ATS failed system trust
[4704:1445043] System Trust failed for [1:0x1c41678c0]
[4704:1445043] TIC SSL Trust Error [1:0x1c41678c0]: 3:0
[4704:1445043] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)
(Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made."

注:

当设备上安装根CA证书并受信任时,启用ATS的HTTPS通信将正常工作,不会出现任何错误。但我不希望用户在设备上手动安装并信任根CA。

代码段:

func getRequest(){  
  let requestUrl = “https://server.test.com/hi.php” //url modified
        let configuration = URLSessionConfiguration.default  
        var request = try! URLRequest(url: requestUrl, method: .get)  

        let session = URLSession(configuration: configuration,  
                                 delegate: self,  
                                 delegateQueue: OperationQueue.main)  
        let task = session.dataTask(with: request, completionHandler: { (data, response, error) in  
            print("Data = \(data)")  
            print("Response = \(response)")  
            print("Error = \(error)")  
        })  
          task.resume()  
    }

func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping(URLSession.AuthChallengeDisposition, URLCredential?) -> Swift.Void){

if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {

    let trust = challenge.protectionSpace.serverTrust
    let rootCa = “root"
    if let rootCaPath = NSBundle.mainBundle().pathForResource(rootCa, ofType: "der") {
      if let rootCaData = NSData(contentsOfFile: rootCaPath) {
        let rootCert = SecCertificateCreateWithData(nil, rootCaData).takeRetainedValue()
        SecTrustSetAnchorCertificates(trust, [rootCert])
        SecTrustSetAnchorCertificatesOnly(trust, true) 
    }

    var trustResult: SecTrustResultType = 0
    SecTrustEvaluate(trust, &trustResult)
    if (Int(trustResult) == kSecTrustResultUnspecified ||
      Int(trustResult) == kSecTrustResultProceed) {
        // Trust certificate.
    } else {
      NSLog("Invalid server certificate.")
    }  
  } else {
    challenge.sender.cancelAuthenticationChallenge(challenge)
  }
}
f0brbegy

f0brbegy1#

我认为实际的加密代码看起来是正确的,至少看起来是正确的,但是NSURLSession方面的事情并没有做正确的事情。
若干问题:

  • 用NSURLSession调用challenge.sender上的任何内容都是错误的。这就是你为NSURLConnection做的方式。相反,您必须通过调用提供的回调方法来指定一个行为,该回调方法具有适当的处置(在某些情况下,还具有凭据)。
  • 取消您不想显式处理的质询是错误的。如果您取消了一个挑战,您是在说连接失败比继续更好。通常,您应该使用默认处理,以便其他类型的挑战在发生时不会导致连接失败。所以在else的例子中,你应该做的是:
completionHandler(URLSession.AuthChallengeDisposition.performDefaultHandling, nil)

如果您不这样做,您将破坏诸如代理身份验证之类的功能,并且它可能在其他情况下也会破坏。

  • 当你得到一个无效的证书时,你应该取消请求。您拥有:
NSLog("Invalid server certificate.")

添加如下内容:

completionHandler(URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge, nil)
  • 在成功验证凭据后,您应该接受凭据。如果你有//信任证书

添加如下内容:

let credential = NSURLCredential(forTrust: challenge.protectionSpace.serverTrust)
completionHandler(URLSession.AuthChallengeDisposition.useCredential, credential);

相关问题