【问题标题】:NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802 in iOS10, 2017NSURLSession/NSURLConnection HTTP 加载失败 (kCFStreamErrorDomainSSL, -9802 in iOS10, 2017
【发布时间】:2017-06-10 19:53:59
【问题描述】:

这不是一个重复的问题,请继续阅读。我正在将我的应用程序中已弃用的代码升级到 iOS10 合规性。

错误: NSURLSession 给我带来了麻烦,这个臭名昭著的错误以及 9806 和 9801,取决于我在 .plist 文件中放置的内容:

NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)

我的代码: 在我的 Info.plist 文件中,我有:

<key>NSAppTransportSecurity</key>
    <dict>
        <key>NSExceptionDomains</key>
        <dict>
            <key>https://my.own-server.com</key>
            <dict>
                <key>NSIncludesSubdomains</key>
                <true/>
                <key>NSExceptionAllowInsecureHTTPSLoads</key>
                <true/>
                <key>NSExceptionRequiresForwardSecrecy</key>
                <true/>
                <key>NSExceptionMinimumTLSVersion</key>
                <string>TLSv1.0</string>
                <key>NSThirdPartyExceptionAllowInsecureHTTPSLoads</key>
                <false/>
                <key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
                <false/>
                <key>NSThirdPartyExceptionMinimumTLSVersion</key>
                <string>TLSv1.0</string>
                <key>NSRequiresCertificateTransparency</key>
                <false/>
            </dict>
        </dict>
        <key>NSAppTransportSecurity</key>
        <dict>
            <key>NSAllowsArbitraryLoads</key>
            <false/>
        </dict>
    </dict>

在我的 ObjectiveC 代码中,我有这个:

NSURLSessionConfiguration *defaultConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session __unused = [NSURLSession sessionWithConfiguration:defaultConfiguration delegate:[PortalRequest alloc] delegateQueue:[NSOperationQueue mainQueue]]; operationQueue:[NSOperationQueue mainQueue]];
    requestContainer.sessionDataTask = [session dataTaskWithRequest:request];
[self.sessionDataTask resume];

在调用 URLSession 的类的 DELEGATE 方法中,我可以看到 didReceiveChallenge:

LOG: ** NSURLSession IOS10 ** - didReceiveChallenge called

...最后我得到了错误:

[TIMESTAMP] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9806)

服务器 其他答案中提出的解决方案都不起作用,是因为 Apple 的 2017 年截止日期吗? https://techcrunch.com/2016/06/14/apple-will-require-https-connections-for-ios-apps-by-the-end-of-2016/ 根据这个在线安全分析工具,https://www.ssllabs.com/ssltest/analyze.html 后端确实支持 TLS 1.2

关于如何解决这个问题的任何想法? 你知道在哪里可以找到一些 iOS 示例代码来 100% 确定我指向的端点是无罪的吗?

更新 这段代码对我有用,有什么意见吗?:

- (void)URLSession:(NSURLSession *)session
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
 completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * __nullable credential))completionHandler{
    NSLog(@"*** KBRequest.NSURLSessionDelegate - didReceiveChallenge IOS10");

    if([challenge.protectionSpace.authenticationMethod
        isEqualToString:NSURLAuthenticationMethodServerTrust])
    {
        if([challenge.protectionSpace.host
            isEqualToString:@"engine.hello-indigo.com"])
        {
            NSURLCredential *credential =
            [NSURLCredential credentialForTrust:
             challenge.protectionSpace.serverTrust];
            completionHandler(NSURLSessionAuthChallengeUseCredential,credential);
        }
        else
            completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
    }
}

【问题讨论】:

  • 如果您正在实现自己的身份验证挑战处理,我的第一个猜测是其中的错误。你能发布那个方法的内容吗?
  • 你如何解决你的问题?因为我有 http 音频流并且 NSURLConnection 完成错误 - 代码 -1002
  • @Genevios 我解决了,看看我的问题的更新。它有效,没有人提出更好的主意,所以我认为它很好。关于您的代码 1002 错误,请检查您在 URL stackoverflow.com/questions/26647423/… 中使用 https
  • @Josh 哦,我的朋友我使用音频流,我怎么理解音频流没有 https ......这是真的还是假的?你觉得怎么样?
  • @Genevios 听起来很复杂,但是您正在将此音频流发送到某个服务器地址,对吗?此地址必须以 http 或 https 开头。

标签: ios ssl nsurlsession nsurlsessiontask


【解决方案1】:

尝试将 NSExceptionRequiresForwardSecrecy 设置为 false。 但是,您的服务器确实满足传输层安全 (TLS) 协议版本的最低要求,您的服务器连接密码可能不支持前向保密。

协商的传输层安全 (TLS) 版本必须是 TLS 1.2。默认情况下,尝试在没有 TLS/SSL 保护的情况下或使用旧版本的 TLS/SSL 进行连接时会被拒绝。

连接必须使用 AES-128 或 AES-256 对称 密码。

协商的 TLS 连接密码套件必须支持完美 通过椭圆曲线 Diffie-Hellman Ephemeral 实现前向保密 (PFS) (ECDHE) 密钥交换,并且必须是以下之一:

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

【讨论】:

  • 安全工具显示所有这些密码套装都受支持。调用委托方法 didReceiveChallenge 后立即发生错误(如上面我的最新编辑所示)
【解决方案2】:

我终于解决了这个问题! 我从 .plist 文件中取出异常,并将这段代码添加到 didReceiveChallenge Delegate 方法中:

- (void)URLSession:(NSURLSession *)session
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
 completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * __nullable credential))completionHandler{
    NSLog(@"*** KBRequest.NSURLSessionDelegate - didReceiveChallenge IOS10");
    completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:[[challenge protectionSpace] serverTrust]]);
}

这篇文章非常有用: http://timekl.com/blog/2015/08/21/shipping-an-app-with-app-transport-security/

【讨论】:

  • @dgatwood 你是对的,但没有人在任何地方解释如何“正确”地做到这一点。如果我还有时间,我会尝试修复它。现在,我需要在我浪费在这个陷阱上的所有时间之后重新获得速度,并将我的应用程序放到商店中。
  • 你绝对不能用这个 hack 在应用商店上发布这个。你的应用几乎肯定会被拒绝。我已经发布了一个完成处理程序的示例,它从您的应用程序包中加载自定义根证书并验证请求。
  • 您介意分享您的示例作为答案吗?如果它有效,我保证一个绿色的勾号。 @dgatwood
【解决方案3】:

为避免完全破坏 TLS(更不用说其他形式的身份验证),您应该执行以下操作:

- (void)URLSession:(NSURLSession *)session
    didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
      completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition,
                                  NSURLCredential *credential))completionHandler
    {
        NSURLProtectionSpace *protectionSpace = [challenge protectionSpace];
        if ([protectionSpace authenticationMethod] == NSURLAuthenticationMethodServerTrust) {
            // Load our trusted root certificate from the app bundle.
            SecTrustRef trust = [protectionSpace serverTrust];
            NSURL *certificatePath = [[NSBundle mainBundle] URLForResource:@"customRootCert" ofType:@"der"];
            NSData *certificateData = [NSData dataWithContentsOfURL:resourcePath];
            SecCertificateRef trustedCert = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certData);

            // Change the trust object to trust our root cert.
            trust = addAnchorToTrust(trust, trustedCert);

            SecTrustResultType secresult = kSecTrustResultInvalid;
            if (SecTrustEvaluate(trust, &secresult) != errSecSuccess) {
                // Something went horribly wrong.
                completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
                return;
            }

            switch (secresult) {
                case kSecTrustResultUnspecified: // The OS trusts this certificate implicitly.
                case kSecTrustResultProceed: // The user explicitly told the OS to trust it.
                {
                    NSURLCredential *credential =
                        [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
                    completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, credential)
                    return;
                }
                default:
                    /* It's somebody else's key/cert. Fall through. */
            }
            completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
        } else {
            // If we aren't checking the server's public key, just use
            // the default behavior.
            completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
        }
    }

请注意,此代码未经编译且未经测试,因此请随时修复拼写错误和其他错误。

【讨论】:

  • 根据您的建议(并将其添加到上面的问题中),我编写了一个同样有效的 sn-p。你认为它安全吗?谢谢。
  • 不,这不安全。您发布的代码意味着任何人都可以为任何证书提供该主机名的任何密钥。它有效地将您的应用程序的请求安全性降低为未加密的 HTTP,如果您要这样做,您不妨只使用 HTTP 并请求例外(祝您好运)。
猜你喜欢
  • 2015-09-04
  • 2016-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-29
  • 2016-01-18
  • 1970-01-01
  • 2015-10-18
相关资源
最近更新 更多