【问题标题】:CFNetwork SSLHandshake failed iOS 9CFNetwork SSLHandshake 失败 iOS 9
【发布时间】:2015-08-23 14:35:54
【问题描述】:

是否有人使用 iOS 9 beta 1 遇到过这个问题?

我使用标准 NSURLConnection 连接到网络服务,一旦调用网络服务,我就会收到以下错误。这目前适用于 iOS 8.3

可能的测试版错误?任何想法或想法都会很棒!我知道它在 iOS 9 开发的早期阶段

这是完整的错误:

CFNetwork SSLHandshake 失败 (-9824) NSURLSession/NSURLConnection HTTP 加载失败 (kCFStreamErrorDomainSSL, -9824)

 NSURLRequest * urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://mywebserviceurl"]];
        NSURLResponse * response = nil;
        NSError * error = nil;
        NSData * data = [NSURLConnection sendSynchronousRequest:urlRequest
                                                  returningResponse:&response
                                                              error:&error];

【问题讨论】:

    标签: ios ssl nsurlconnection ios9


    【解决方案1】:

    iOS 9 和 OSX 10.11 要求您计划从中请求数据的所有主机都使用 TLSv1.2 SSL,除非您在应用的 Info.plist 文件中指定异常域。

    Info.plist 配置的语法如下所示:

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

    如果您的应用程序(例如第三方网络浏览器)需要连接到任意主机,您可以这样配置:

    <key>NSAppTransportSecurity</key>
    <dict>
        <!--Connect to anything (this is probably BAD)-->
        <key>NSAllowsArbitraryLoads</key>
        <true/>
    </dict>
    

    如果您必须这样做,最好更新您的服务器以使用 TLSv1.2 和 SSL,如果他们还没有这样做的话。这应该被视为一种临时解决方法。

    截至今天,预发布文档未以任何特定方式提及任何这些配置选项。完成后,我将更新答案以链接到相关文档。

    【讨论】:

    • 应用传输安全 (ATS) 允许应用向其 Info.plist 文件添加声明,该文件指定需要与其进行安全通信的域。 ATS 可防止意外泄露,提供安全的默认行为,并且易于采用。无论您是创建新应用还是更新现有应用,都应尽快采用 ATS。如果你正在开发一个新的应用程序,你应该只使用 HTTPS。如果您有一个现有的应用程序,则应立即尽可能多地使用 HTTPS,并制定计划以尽快迁移应用程序的其余部分。
    • @StevenPeterson 嘿,史蒂夫,我似乎无法让异常域示例正常工作,您是否偶然有任何想法,我只是复制并粘贴到 .plist 中,将 TLSv1.1 更改为 TLSv1.0 并且域到我们的域,没有 https:// 等
    • 抱歉聊了这么久,但我发现我需要禁用 NSTemporaryExceptionRequiresForwardSecrecy
    • @RashmiRanjanmallick NSTemporaryExceptionMinimumTLSVersion 用于告诉 ATS 您正在使用非 1.2 服务器。例如,如果您尝试连接到使用 TLS 1.0 的主机,请使用此选项。您还必须使用设置为 false 的 NSTemporaryExceptionRequiresForwardSecrecy,如上面的 user3099837 所示。
    • ste.vn/2015/06/10/… - 这是答案来源的博客。
    【解决方案2】:

    在 iOS 10+ 中,TLS 字符串的格式必须为“TLSv1.0”。它不能只是“1.0”。 (叹气)


    其他答案的以下组合有效。

    假设您正在尝试连接到只有 TLS 1.0 的主机 (YOUR_HOST.COM)。

    将这些添加到您应用的 Info.plist 中

    <key>NSAppTransportSecurity</key>
    <dict>
        <key>NSExceptionDomains</key>
        <dict>
            <key>YOUR_HOST.COM</key>
            <dict>
                <key>NSIncludesSubdomains</key>
                <true/>
                <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
                <true/>
                <key>NSTemporaryExceptionMinimumTLSVersion</key>
                <string>TLSv1.0</string>
                <key>NSTemporaryExceptionRequiresForwardSecrecy</key>
                <false/>
            </dict>
        </dict>
    </dict>
    

    【讨论】:

    • 似乎添加 NSTemporaryExceptionRequiresForwardSecrecy 对我有用,谢谢!
    • 这个版本在 iOS9.1 上对我不起作用 - 我需要在其他答案之一中使用 TLSVersion 字符串格式 NSTemporaryExceptionMinimumTLSVersionTLSv1.1
    • 这可行,但我的问题是:这是否意味着我的应用在这些参数打开且数据未加密时不使用 ssl?
    【解决方案3】:

    欲了解更多信息Configuring App Transport Security Exceptions in iOS 9 and OSX 10.11

    奇怪的是,您会注意到连接尝试更改 http 协议到 https 以防止代码中的错误 您可能不小心错误地配置了 URL。在某些情况下,这 可能确实有效,但也令人困惑。

    Shipping an App With App Transport Security 涵盖了一些很好的调试技巧

    ATS 故障

    大多数 ATS 故障将显示为 CFErrors,代码在 -9800 系列。这些在 Security/SecureTransport.h 头文件中定义

    2015-08-23 06:34:42.700 SelfSignedServerATSTest[3792:683731] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813)
    

    CFNETWORK_DIAGNOSTICS

    将环境变量 CFNETWORK_DIAGNOSTICS 设置为 1,以便 在控制台上获取有关失败的更多信息

    nscurl

    该工具将运行多种不同的 ATS 组合 例外,尝试安全连接到每个下的给定主机 ATS 配置并报告结果。

    nscurl --ats-diagnostics https://example.com
    

    【讨论】:

    • 只有一点,nscurl 仅在 Mac OS X "El Capitan" 中可用
    • 另一个调试技巧,检查您的服务器正在使用哪个 TLS 连接密码: curl -v https://
    • 如果 curl 顺利通过所有步骤,有什么想法会导致问题吗?
    • @onmyway133 你能补充说明如何“将环境变量 CFNETWORK_DIAGNOSTICS 设置为 1”吗?
    • @YakirNa 你可以在这里阅读如何做到这一点nshipster.com/launch-arguments-and-environment-variables 这很简单:)
    【解决方案4】:

    如果您的后端使用安全连接,您可以使用 NSURLSession

    CFNetwork SSLHandshake failed (-9801)
    NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9801)
    

    您需要检查您的服务器配置,尤其是获取 ATS 版本和 SSL 证书信息:

    不只是通过设置NSExceptionAllowsInsecureHTTPLoads = YES 允许不安全的连接,而是需要允许降低安全性以防您的服务器不满足最低要求(v1.2 ) 用于 ATS(或更好地修复服务器端)。

    允许降低单个服务器的安全性

    <key>NSExceptionDomains</key>
    <dict>
        <key>api.yourDomaine.com</key>
        <dict>
            <key>NSExceptionMinimumTLSVersion</key>
            <string>TLSv1.0</string>
            <key>NSExceptionRequiresForwardSecrecy</key>
            <false/>
        </dict>
    </dict>
    

    使用 openssl 客户端调查证书并使用 openssl 客户端获取您的服务器配置:

    openssl s_client  -connect api.yourDomaine.com:port //(you may need to specify port or  to try with https://... or www.)
    

    ..在最后找到

    SSL-Session:
        Protocol  : TLSv1
        Cipher    : AES256-SHA
        Session-ID: //
        Session-ID-ctx: 
        Master-Key: //
        Key-Arg   : None
        Start Time: 1449693038
        Timeout   : 300 (sec)
        Verify return code: 0 (ok)
    

    应用传输安全 (ATS) 需要传输层安全 (TLS) 协议版本 1.2。

    Requirements for Connecting Using ATS:

    使用应用传输安全 (ATS) 的 Web 服务连接要求涉及服务器、连接密码和证书,如下所示:

    证书必须使用以下类型的密钥之一进行签名:

    • 摘要长度至少为 256(即 SHA-256 或更大)的安全散列算法 2 (SHA-2) 密钥

    • 椭圆曲线加密 (ECC) 密钥,大小至少为 256 位

    • 长度至少为 2048 位的 Rivest-Shamir-Adleman (RSA) 密钥 无效的证书会导致硬故障并且没有连接。

    以下连接密码支持前向保密 (FS) 和工作 使用 ATS:

    TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA

    更新:原来openssl只提供最小协议版本协议:TLSv1 links

    【讨论】:

    • 问题仍然是是否可以解释 openssl 信息以查明服务器是否满足要求。还有协议:TLSv1 可能是主要版本而不是 1.x
    • 我把它设为通用,以防使用端口
    • 答案留下的问题多于回答的问题。似乎一个问题可能是 openssl 报告和 Apple 文档之间的映射。无法从 openssl 输出确定是否支持 TLS 1.2。答案也不允许确定是否支持完美前向保密。
    【解决方案5】:

    经过两天的尝试和失败,对我有用的是womble的这段代码

    有了一个变化,根据这个post,我们应该停止使用与那种约定的 NSExceptionDomains 字典关联的子键

      NSTemporaryExceptionMinimumTLSVersion
    

    并在新公约中使用

      NSExceptionMinimumTLSVersion
    

    改为。

    apple documentation

    我的代码

    <key>NSAppTransportSecurity</key>
        <dict>
            <key>NSExceptionDomains</key>
            <dict>
                <key>YOUR_HOST.COM</key>
                <dict>
                    <key>NSExceptionAllowsInsecureHTTPLoads</key>
                    <true/>
                    <key>NSExceptionMinimumTLSVersion</key>
                    <string>TLSv1.0</string>
                    <key>NSExceptionRequiresForwardSecrecy</key>
                    <false/>
                    <key>NSIncludesSubdomains</key>
                    <true/>
                </dict>
            </dict>
        </dict>
    

    【讨论】:

      【解决方案6】:

      另一个有用的工具是 nmap (brew install nmap)

      nmap --script ssl-enum-ciphers -p 443 google.com
      

      给出输出

      Starting Nmap 7.12 ( https://nmap.org ) at 2016-08-11 17:25 IDT
      Nmap scan report for google.com (172.217.23.46)
      Host is up (0.061s latency).
      Other addresses for google.com (not scanned): 2a00:1450:4009:80a::200e
      PORT    STATE SERVICE
      443/tcp open  https
      | ssl-enum-ciphers: 
      |   TLSv1.0: 
      |     ciphers: 
      |       TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (secp256r1) - A
      |       TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (secp256r1) - A
      |       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (secp256r1) - A
      |       TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
      |       TLS_RSA_WITH_3DES_EDE_CBC_SHA (rsa 2048) - C
      |       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (secp256r1) - A
      |       TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A
      |     compressors: 
      |       NULL
      |     cipher preference: server
      |   TLSv1.1: 
      |     ciphers: 
      |       TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (secp256r1) - A
      |       TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (secp256r1) - A
      |       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (secp256r1) - A
      |       TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
      |       TLS_RSA_WITH_3DES_EDE_CBC_SHA (rsa 2048) - C
      |       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (secp256r1) - A
      |       TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A
      |     compressors: 
      |       NULL
      |     cipher preference: server
      |   TLSv1.2: 
      |     ciphers: 
      |       TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (secp256r1) - A
      |       TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 (secp256r1) - A
      |       TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (secp256r1) - A
      |       TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (secp256r1) - A
      |       TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 (secp256r1) - A
      |       TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (secp256r1) - A
      |       TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 (secp256r1) - A
      |       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (secp256r1) - A
      |       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (secp256r1) - A
      |       TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (secp256r1) - A
      |       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (secp256r1) - A
      |       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (secp256r1) - A
      |       TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (secp256r1) - A
      |       TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (secp256r1) - A
      |       TLS_RSA_WITH_3DES_EDE_CBC_SHA (rsa 2048) - C
      |       TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
      |       TLS_RSA_WITH_AES_128_CBC_SHA256 (rsa 2048) - A
      |       TLS_RSA_WITH_AES_128_GCM_SHA256 (rsa 2048) - A
      |       TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A
      |       TLS_RSA_WITH_AES_256_CBC_SHA256 (rsa 2048) - A
      |       TLS_RSA_WITH_AES_256_GCM_SHA384 (rsa 2048) - A
      |     compressors: 
      |       NULL
      |     cipher preference: client
      |_  least strength: C
      
      Nmap done: 1 IP address (1 host up) scanned in 5.48 seconds
      

      【讨论】:

      • 对调试证书问题非常有用
      【解决方案7】:

      当我使用有缺陷/崩溃的 Cordova iOS 版本时,有时会在日志中显示此错误。当我升级或降级cordova iOS时它就消失了。

      我连接的服务器使用的是 TLSv1.2 SSL,所以我知道这不是问题。

      【讨论】:

        【解决方案8】:

        在您的项目.plist 文件中添加此权限:

        <key>NSAppTransportSecurity</key>
        <dict>
            <!--Connect to anything (this is probably BAD)-->
            <key>NSAllowsArbitraryLoads</key>
            <true/>
        </dict>
        

        【讨论】:

          【解决方案9】:

          Info.plist 配置的语法

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

          【讨论】:

            【解决方案10】:

            更新答案(WWDC 2016 后):

            iOS 应用程序将需要安全的 HTTPS 连接 2016. 尝试关闭 ATS 可能会导致您的应用在未来被拒绝。

            App Transport Security 或 ATS 是 Apple 在 iOS 9 中引入的一项功能。启用 ATS 后,它会强制应用通过 HTTPS 连接而不是不安全的 HTTP 连接到 Web 服务。

            但是,开发人员仍然可以关闭 ATS 并允许他们的应用通过 HTTP 连接发送数据,如上述答案中所述。 2016 年底,Apple 将对所有希望将其应用提交到 App Store 的开发者强制执行 ATS。链接

            【讨论】:

              【解决方案11】:

              我测试的设备设置了错误的时间。因此,当我尝试使用即将用完的证书访问页面时,它会拒绝访问,因为该设备虽然证书已过期。要修复,请在设备上设置适当的时间!

              【讨论】:

                猜你喜欢
                • 2015-09-21
                • 1970-01-01
                • 2016-02-11
                • 1970-01-01
                • 2016-04-08
                • 2015-07-29
                • 1970-01-01
                相关资源
                最近更新 更多