ios - NSURLSession 完成处理程序意味着如果 didReceiveChallenge 被自动调用
问题描述
有人可以解释我是否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);
}
}
解决方案
在进一步讨论之前,我应该首先指出,这样做几乎总是一个错误。您可以从LetsEncrypt等各种团体获得免费的 TLS 证书。因此,除非您有一些非常不寻常的用例(例如需要为未连接到公共 Internet 的设备提供信任,通过链接本地网络进行通信),否则您最好不要这样做,而只是安装测试服务器上的真实 TLS 证书。
照这样说....
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 开发人员文档中的正确覆盖 TLS 链验证,但通常您可以通过以下任一方式执行此操作
- 提供用于签署假证书的根证书(不带密钥)的副本,然后将该根证书添加到一组有效的根证书中,然后重新评估证书。
- 提供伪造证书的公钥副本,并断言它与预期的密钥匹配。
无论采用哪种方法,您都应该回退到默认处理,这样如果您将自签名证书替换为真实证书,它将“正常工作”。
推荐阅读
- python - 具有 tensorflow 召回率超过 100 的神经网络
- css - ng-deep 导致 Angular 中的 mat-select 出现问题
- java - 将方法和参数传递给 Java 中的函数
- c++ - int return 类型的递归函数 c++,即使它的主体上没有返回指令,steel 也能工作
- python - 如何从Django中的属性中单独获取变量的值
- angular - AddApiAuthorization 的默认设置(脚手架 Angular + IdentityServer4)
- java - 单例双重检查锁定在高版本JDK(例如jdk11、14)中是否仍然需要volatile?
- java - 使用带有 aes-cbc-256 的 openssl 解密文件
- php - 我有一个变量,但它没有被读取为任何东西
- javascript - 如何使 Bootstrap 4 Card 在滚动时粘在顶部