2

我正在开发一个使用 https 与服务器通信的 iOS Enterprise POS 应用程序。我查看了在 iOS7 GM 中接收 SSL 错误 - “AddTrust External CA Root”不受信任?自签名 CA 和自签名证书之间的区别,通常在网上搜索,但我没有得到任何结果。

该应用程序使用 http 或 https 协议在 iOS6.1 上运行良好。它也可以通过 http 在 iOS 7GM 上正常工作,但不能通过 https - 它在发送到服务器的第一条消息时失败。在应用程序方面,我处理身份验证挑战:

- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge: (NSURLAuthenticationChallenge *)challenge 
{
    [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] 
         forAuthenticationChallenge:challenge];
}

之后我收到一个回调:

- (void)connectionDidFinishLoading:(NSURLConnection *)connection

不是:

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error

我相信这意味着客户端和服务器成功协商了连接,就加密协议达成一致等。不幸的是,尽管返回似乎成功(就网络堆栈而言),但我在 AMF 有效负载中返回了 0 个字节的数据。

这是有趣的部分 - 在服务器端 (JBoss4.2.3) 我可以断点并检查包含 AMFRequest 的 httpRequest 正文。通过 http,我总是在正文中获得 384 个字节。通过 https,如果客户端是 iOS 6.1,我会得到 384 个字节,但如果客户端是 iOS 7,我会得到 0 个字节。我认为这是因为服务器“正常”地接受了 https 请求,没有错误、安全违规等。

多了一个数据点。如果我在客户端运行Charles,则使用 iOS 7 模拟器在 https 上一切正常。我可以在 Charles 和服务器上看到我的 384 字节 AMFRequest。Charles 作为 http 代理工作 - 但应用程序对此一无所知,那么为什么插入 Charles 作为中介使其工作?我已经安装了 Charles 的证书,所以我认为它通过 SSL 与服务器通信(不确定)。

感谢您的任何帮助或建议。

更新:我实施了 Apple 推荐的方法:

- (void)connection: (NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
    traceMethod();
    SecTrustRef trust = challenge.protectionSpace.serverTrust;
    NSURLCredential *credential = [NSURLCredential credentialForTrust: trust];
    [challenge.sender useCredential: credential
         forAuthenticationChallenge: challenge];
}

但它得到的结果与旧的(iOS 5 之前的)方式完全相同。

4

4 回答 4

1

After considerable research I opened a incident with Apple Developer Tech Support and eventually have an explanation.

I've been able to confirm that Apple made a change in iOS 7 as a "recommended countermeasure to the BEAST attack", which is a "man in the middle" attack against the SSL TLS protocol - see this article on CERT.

The ideal solution would be to change the JBoss (Tomcat) ssl connector to use:

sslProtocol="TLSv1.2"

Unfortunately the stock JBoss4.2.3GA implementation is unable to handle TLSv1.1 or TLSv1.2, or process messages that use this countermeasure. It appears the only solution is to upgrade the JBoss configuration. That requires significant JBoss changes - see this JBoss article.

An alternative is to re-write the networking methods to use a lower level framework (CFSocketStream instead of NSURLConnection) and disable the BEAST countermeasure. That has two downsides - it re-exposes the security vulnerability and it is a non-trivial implementation that would need thorough testing (especially simulating network edge cases).

In my case time does not permit changes of such magnitude prior the Holiday season. My client is a major retailer and their IT department locks down the environment in mid-October.

Perhaps this information will help someone else.

于 2013-10-04T17:30:47.163 回答
0

NSURLConnection 和 Amazons ELB & EC2 实例存在问题,其中 ELB 未启用 TLS v1.2,导致 15-50% 的请求未正确处理(正文中带有 JSON 的 HTTPS PUT)。转向 TLS v1.2 解决了这个问题……我挠头试图找出这个事实背后的逻辑。

于 2014-02-16T22:11:50.007 回答
0

API 中的 SSL 肯定发生了变化

我不太了解 SSL 的工作原理,但我注意到 MKNetworkKit 正在使用现已在 iOS 7 中弃用的名为kSecTrustResultConfirm的常量(可在安全框架的 SecTrust.h 中找到):

@constant kSecTrustResultConfirm 表示在继续之前需要与用户确认。重要提示:从 OS X 10.5 开始,SecTrustEvaluate 或 SecTrustSettings API 不再返回或支持此值;它在 OS X 10.9 及更高版本以及 iOS 中已弃用。

也许这是朝着正确方向发展的一点?无论如何,祝你好运解决你的问题!

这是某人在 MKNetworkKit 中“修复”此问题的提交差异: https ://github.com/MugunthKumar/MKNetworkKit/commit/c28959805991bb8f0e99ede9c822e985b41f6fc9 (向下滚动到 L:1142)

于 2013-09-26T19:32:14.287 回答
0

让 iOS 7 与 Jboss eap 6.0.1 resteasy 方法对话时遇到了同样的问题。

答案是将 ssl 标签协议设置为 TLSv1.2。例如

<connector name="https" protocol="HTTP/1.1" scheme="https" socket-binding="https" secure="true">
   <ssl name="ssl" key-alias="awssink" password="keystore-password" certificate-key-file="${jboss.server.config.dir}/attimoto.jks" verify-client="false" protocol="TLSv1.2"/>
</connector>

现在我们正在使用 Bearer 令牌来访问 restful 方法,因此使用 AFNetworking 2+ 我们可以执行以下操作:

NSString *secureURLString = [secureBaseURLString stringByAppendingString:BURP];
NSLog(@"the secure url is %@\n\n", secureURLString);

// set up the request manager
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
// allow invalid certificates
manager.securityPolicy.allowInvalidCertificates = YES;

//Note we dont deal with pinned certificates since we are doing bearer token    

manager.responseSerializer = [AFHTTPResponseSerializer serializer];

manager.requestSerializer = [AFHTTPRequestSerializer serializer];
[manager.requestSerializer setValue:BEARER_TOKEN forHTTPHeaderField:@"Authorization"];
//Note we do NOT use setAuthorizationHeaderFieldWithToken:BEARER_TOKEN];
//Ultimately you want just a header like this
// "Authorization: Bearer textofthebearertoken"
//So BEARER_TOKEN is literally @"Bearer thetextofthebearertoken"

[manager GET:secureURLString
  parameters:nil
     success:^(AFHTTPRequestOperation *operation, id responseObject) {
         NSLog(@" RESPONSE RETURNED %@\n\n", responseObject);

     } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
         NSLog(@"error = %@", error);
     }];
于 2013-12-03T16:11:11.667 回答