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
我开发了一个 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