IOS9 NSURLSession 出现 SSL 错误

IOS9 SSL error with NSURLSession

我开发了一个 IOS 应用程序,它使用 HTTPS 与服务器通信(我也是服务器的开发者,它嵌入了一个 Tomcat 服务器)。

此应用程序在 IOS8 上没有任何问题,但在 IOS9 上没有任何问题。

发送 HTTPs 请求时出现以下错误:

Session download has failed : Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo=0x7fa9c44b2e40 {NSErrorFailingURLStringKey=https://127.0.0.1:8443/MyServer/MyApp, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorDomainKey=3, NSErrorFailingURLKey=https://127.0.0.1:8443/MyServer/MyApp, _kCFStreamErrorCodeKey=-9802, NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made.}

根据 Apple 文档,当错误代码=-1200 发生时,这是因为 TLSv1.1 而不是 TLSv1.2。我已经使用 openSSL 命令进行了验证,我的服务器正在使用 TLSv1.2。

当在 info.plist 中设置 属性 NSAllowsArbitraryLoads = true 时,错误消失但我不想保持这样。

我的服务器使用的是自签名证书,这可能是问题的原因? 下面是我用于 didReceiveChallenge

的代码
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler {

[RequestURLUtilities dumpChallenge:challenge];


if (challenge.protectionSpace != Nil) {
    NSURLProtectionSpace *protection = challenge.protectionSpace;

    SecTrustRef sslState = protection.serverTrust;
    if (sslState == Nil) {
        NSLog(@"%s Warning: empty serverTrust",__PRETTY_FUNCTION__);
    }


    if ([protection.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {

        NSLog(@"%s => NSURLAuthenticationMethodServerTrust", __PRETTY_FUNCTION__);
        // warning normaly I should check the validity of the SecTrustRef before to trust
        NSURLCredential* credential = [NSURLCredential credentialForTrust:sslState];

        // Put in command for test

       completionHandler(NSURLSessionAuthChallengeUseCredential, credential);

    } else {
        NSLog(@"%s => Called for another challenge", __PRETTY_FUNCTION__);
       completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, NULL);
    }

}

我应该先创建自己的 CA,然后再创建自己的证书吗?如何进行?什么东西少了?任何帮助将不胜感激。

塞巴斯蒂安。

在与 Apple 支持人员讨论后,问题是由自签名证书引起的。

ATS 只信任由知名 CA 签名的证书,拒绝所有其他证书。因此,使用自签名证书的唯一解决方案是使用 NSExceptionDomains 设置异常。

不幸的是,您需要从主要 CA 获得证书或设置一个例外,这只是一个临时修复。您真的应该修复您的 SSL 并在 SSL Labs

重新测试它

右键单击您的 Info.plist 并 select 作为源代码打开。以下代码将允许您仅绕过您的服务器。文档是 here

<key>NSAppTransportSecurity</key>
<dict>
  <key>NSExceptionDomains</key>
  <dict>
    <key>yourserver.com</key>
    <dict>
      <!--Include to allow subdomains-->
      <key>NSIncludesSubdomains</key>
      <true/>
      <!--Include to allow HTTP requests-->
      <key>NSExceptionAllowsInsecureHTTPLoads</key>
      <true/>
      <!--Include to specify minimum TLS version-->
      <key>NSExceptionMinimumTLSVersion</key>
      <string>TLSv1.1</string>
      <key>NSExceptionRequiresForwardSecrecy</key>
      <false/>
    </dict>
  </dict>
</dict>

您也可以通过将 info.plist 编辑为 属性 列表来进行设置。看这篇文章WORKING WITH APPLE’S APP TRANSPORT SECURITY