这不是重复的问题,请继续阅读。我正在将我的应用中已弃用的代码升级到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%确定我指向的端点是无罪吗?
UPDATE 这段代码对我有用,有什么意见吗?:
- (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);
}
}
答案 0 :(得分:0)
尝试将NSExceptionRequiresForwardSecrecy设置为false。 但是,您的服务器确实满足传输层安全性(TLS)协议版本的最低要求,您的服务器Connection-Cipher可能不支持前向保密。
协商的传输层安全性(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
答案 1 :(得分:0)
我终于解决了这个问题! 我从.plist文件中取出了异常,并将此代码添加到didReceiveChallenge Delegate方法中:
DEBUG:__main__:You cannot see me anymore: **************
INFO:__main__:You cannot see me anymore: ***********
WARNING:__main__:You cannot see me anymore: *********
ERROR:__main__:You cannot see me anymore: ***
CRITICAL:__main__:You cannot see me anymore: ******
这篇文章非常有用: http://timekl.com/blog/2015/08/21/shipping-an-app-with-app-transport-security/
答案 2 :(得分:0)
为了避免完全破坏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);
}
}
请注意,此代码未经编译且未经测试,因此请随时修复拼写错误和其他错误。