Ios 为什么HTTPS NSURLSession连接在每个域中只被质询一次?
当通过HTTPS连接到服务器时,我实现了Ios 为什么HTTPS NSURLSession连接在每个域中只被质询一次?,ios,cocoa-touch,https,nsurlsession,Ios,Cocoa Touch,Https,Nsurlsession,当通过HTTPS连接到服务器时,我实现了nsurlsessionelegate方法URLSession:didReceiveChallenge:completionHandler:,以实现一些自定义功能 问题在于,只有在第一次发出请求时才会调用此委托方法(后续请求不会调用此方法)。我的自定义功能要求为每个请求调用委托方法 下面是一个例子: - (IBAction)reload:(id)sender { NSURLSession *session = [NSURLSession sessi
nsurlsessionelegate
方法URLSession:didReceiveChallenge:completionHandler:
,以实现一些自定义功能
问题在于,只有在第一次发出请求时才会调用此委托方法(后续请求不会调用此方法)。我的自定义功能要求为每个请求调用委托方法
下面是一个例子:
- (IBAction)reload:(id)sender {
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration] delegate:self delegateQueue:nil];
// Note that https://www.example.com is not the site I'm really connecting to.
NSURL *URL = [NSURL URLWithString:@"https://www.example.com"];
NSMutableURLRequest *URLRequest = [NSMutableURLRequest requestWithURL:URL];
[[session dataTaskWithRequest:URLRequest
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
// Response received here.
}] resume];
}
#pragma NSURLSessionDelegate
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
{
// Called only for the first request, subsequent requests do no invoke this method.
completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
}
由于我希望URLCredential是每个会话或每个任务的,所以我检查了传递给completionHandler
的NSURLCredential
,发现它有一个持久性
的NSURLCredentialPersistenceForSession
(不可变),这似乎是正确的
我还检查了[nsurlCredentialsStorage allCredentials]
,它是空的,因此它没有在那里缓存凭据
我注意到,如果我随后向另一个域的HTTPS URL发出请求,则该域将调用一次质询,因此是基于每个域的质询
那么,为什么只有一次挑战
编辑
切换到NSURLSessionTaskDelegate
并使用URLSession:task:didReceiveChallenge:completionHandler:
没有任何区别
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
{
completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
}
编辑
编辑由于目前似乎没有办法解决这个问题,我已经提交了一份苹果bug报告:19072802您在这里真正想做的是评估每个请求的服务器凭据的信任度 从较高的层次描述HTTP信任评估,并详细介绍如何实现它 使用SSL/TLS连接到主机时,主机会显示一组加密凭据。您的应用程序(可能是直接的用户)必须评估这些凭据,并决定是否可以信任这些凭据 这就像看某人的驾照或护照,然后决定他们是否是他们所说的人 想象一下,如果你为某人说的每一个单词看一次他的身份证明。那会让泰迪乌斯得逞的!除非这个人改变了,或者他们的身份改变了,否则这是没有意义的。如果服务器或其凭据发生更改,iOS将执行信任评估
这实际上发生在HTTP下面的传输(套接字)层上,但是基金会欣然地暴露了API中的这个更高的级别,比如<代码> NSURLCONNECT/<代码>和
SecureTransport
忽略进程的会话缓存
更详细地描述SecureTransport
会话缓存,并可能提供一些绕过TLS缓存的有趣选项(即与DNS混淆)
目前没有用于清除或修改SecureTransport
TLS会话缓存的API。您可以提交雷达请求此功能
TL;博士
“那么,为什么挑战只有一次?”
第一次TLS信任评估的结果由会话缓存中的SecureTransport
缓存
目前没有办法控制这种特殊的行为
您可以尝试使用其他HTTPS库或框架(如OpenSSL)YMMV。Great information@quellish,正如您所说,目前似乎无法正确绕过TLS会话缓存,因此我提交了一份错误报告19072802@quellish在文档中(您已发布)我发现NSURLSession维护自己的TLS会话缓存。我还注意到,在转移到PROD环境后,我开始发现确实收到挑战的问题并没有被调用,但在PRE-PORD上,我一直都在遇到。我觉得这可能与后端有关。是吗?你找到解决问题的办法了吗?当我搬到PROD环境时,我开始遇到同样的问题。在试生产前,我一直受到挑战。在这一点上,对我来说,它似乎是与后端有关。我最近测试了这个,它似乎是固定的(它总是要求认证)。如果我找到了我的示例项目,我会把它给你。在阅读了Apple文档后,我发现会话级挑战是由服务器负责的。需要查看后端配置/设置。如果有兴趣,请在这里查找“会话级别”。因此,通过在nginx中禁用ssl会话缓存,我的问题得到了解决。