有人可以向我解释如果我使用didReceiveChallenge
向https服务器发出请求后是否自动调用NSURLSession
,如果完成处理程序在didReceiveChallenge
完成后正在调用某些内部方法以及我如何可以访问此完成处理程序?委托方法具有以下内容:
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler
[编辑]
通常,我会在基本实现中看到此方法:
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler
{
if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
{
if([challenge.protectionSpace.host
isEqualToString:@"google.it"])
{
NSURLCredential *credential = [NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust];
completionHandler(NSURLSessionAuthChallengeUseCredential,credential);
}
else
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
}
}
答案 0 :(得分:0)
在继续之前,我应该指出执行其中任何一项几乎总是一个错误。您可以从LetsEncrypt之类的各个组获取免费的TLS证书。因此,除非您有一些非常不寻常的用例(例如需要为未连接到公共Internet的设备提供信任,通过链接本地网络进行通信),否则您通常总是不只需在您的测试服务器上安装一个真正的TLS证书即可。
话虽如此...
只要操作系统需要进行其他确认,就会在会话的委托人(如果非nil)上调用URLSession:didReceiveChallenge:completionHandler:
方法。可能不会为每个请求都调用它,但通常是这样。由于服务器信任评估,因此在每个https请求期间都调用它。
上面的代码可能会让您失败,因为在保护空间不是服务器信任(例如代理身份验证,HTTP基本/摘要身份验证等)的情况下,您不要求默认处理。网络机器只是坐在那里等着你告诉它该怎么做,而忽略了当方法返回时释放通过它的块的事实,因此将永远不会被调用。
您应该这样做:
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler
{
if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
{
if([challenge.protectionSpace.host isEqualToString:@"google.it"])
{
if (/* Manually verify the certificate here in some way */) {
NSURLCredential *credential = [NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust];
completionHandler(NSURLSessionAuthChallengeUseCredential,credential);
} else {
// Evaluation failed. Reject the certificate.
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
}
// Do not fall through for either case above.
return;
}
}
completionHandler(NSURLSes NSURLSessionAuthChallengePerformDefaultHandling, nil);
}
此外,您发布的代码非常不安全,因为您没有做任何事情来验证证书。有关如何执行此步骤的更多信息,请参见Apple开发人员文档中的Overriding TLS Chain Validation Correctly,但通常您可以选择其中一种进行
无论采用哪种方法,您都应该回到默认处理方式,这样,如果您用真实的证书替换了自签名证书,它将“起作用”。
答案 1 :(得分:0)
首先感谢您的宝贵时间。我将尝试更好地解释我的要求。我有两种可能的情况ANY
和SYSTEM_VALIDATED
,因此我应该做以下事情:
ANY
:我应该允许所有证书 SYSTEM_VALIDATED
:我正在构建的框架从App客户端捆绑中读取了一个data.bin文件,并且该文件可以包含该公司拥有的一个或多个CA(证书颁发机构)(案例A)该SDK已提供给我们的要求,也可以包含一个简单的单词“ SYSTEM”(案例B)。在这种情况下,我应该做以下事情
如果我没记错的话,应该通过以下两行完成:
NSURLCredential *credential = [NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust];
completionHandler(NSURLSessionAuthChallengeUseCredential,credential);
案例A我应该进行手动比较并评估证书,也许对于案例B我应该什么都不做,让URL加载系统默认评估服务器信任度
我目前正在阅读此apple docs和此apple docs。我知道我应该对案例A进行手动服务器信任评估,但是对于案例B和任何其他案例,我应该在上面的这两行中调用,还是什么都不做,让URL加载系统处理所有事情?
[编辑]
我忘了提到此请求已发送给服务器公司,该公司使用有效的CA证书支持TLS
1.2。