NSURLSession 的 IOS9 SSL 错误

Posted

技术标签:

【中文标题】NSURLSession 的 IOS9 SSL 错误【英文标题】:IOS9 SSL error with NSURLSession 【发布时间】:2015-07-19 20:51:33 【问题描述】:

我开发了一个 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 文档,当错误 Code=-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,然后再创建自己的证书吗?如何进行?什么不见​​了?任何帮助将不胜感激。

塞巴斯蒂安。

【问题讨论】:

【参考方案1】:

在与 Apple 支持讨论后,问题是由于自签名证书。

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

【讨论】:

这对你有用吗?我应该为我的域设置哪个例外?我已经尝试了几乎所有的组合,但仍然得到错误代码 -1200 ... Apple 声明我们应该添加“NSExceptionAllowsInsecureHTTPLoads”并将其设置为 true,以便可以访问域并出现错误。但我得到的只是一个没有响应的错误。 解决了我的问题,在我的情况下,我的测试域存在问题,没有证书但使用了 HTTPS 协议。为此,唯一的解决方案是在 Info.plist 中将 NSAllowsArbitraryLoads 异常设置为 true。【参考方案2】:

不幸的是,您将需要从主要 CA 获得证书或设置一个只是临时修复的异常。你真的应该修复你的 SSL 并在SSL Labs 测试它

右键单击您的 Info.plist 并选择作为源代码打开。以下代码将允许您仅绕过您的服务器。文档是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

【讨论】:

如果您没有域名,那么唯一的选择是使用 NSAllowsArbitraryLoads,例如:NSAppTransportSecurity

以上是关于NSURLSession 的 IOS9 SSL 错误的主要内容,如果未能解决你的问题,请参考以下文章

NSURLSession HTTP/2 内存泄漏

如何使用 iOS 7 的 NSURLSession 接受自签名 SSL 证书

NSURLSession学习

出于开发目的,如何使用 iOS 7 的 NSURLSession 及其委托方法系列接受自签名 SSL 证书?

NSURLSession详解

iOS网络开发使用NSURLSession