为什么 HTTPS NSURLSession 连接每个域只挑战一次? [英] Why is a HTTPS NSURLSession connection only challenged once per domain?

查看:44
本文介绍了为什么 HTTPS NSURLSession 连接每个域只挑战一次?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当通过 HTTPS 连接到服务器时,我实现了 NSURLSessionDelegate 方法 URLSession:didReceiveChallenge:completionHandler: 以实现一些自定义功能.

When connecting via HTTPS to a server, I implement the NSURLSessionDelegate method URLSession:didReceiveChallenge:completionHandler: to implement some custom functionality.

问题是这个委托方法只在第一次发出请求时被调用(后续请求不会调用这个方法).我的自定义功能要求为每个请求调用委托方法.

The problem is that this delegate method is only being called the first time a request is made (subsequent requests do not invoke this method). My custom functionality requires the delegate method to be called for every request.

这是一个例子:

- (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,所以我检查了传递给 completionHandlerNSURLCredential,我发现它有一个 persistenceNSURLCredentialPersistenceForSession (这是不可变的),这似乎是正确的.

Since I want the URLCredential to be per session or per task, I checked the NSURLCredential that I pass to completionHandler, and I found it has a persistence of NSURLCredentialPersistenceForSession (which is immutable), which seems correct.

我还检查了 [NSURLCredentialStorage allCredentials] 并且它是空的,所以它没有在那里缓存凭据.

I also checked [NSURLCredentialStorage allCredentials] and it's empty, so it's not caching the credentials there.

我注意到,如果我随后向具有不同域的 HTTPS URL 发出请求,则会对该域调用一次质询,因此它是基于每个域的.

I noticed that if I subsequently make a request to a HTTPS URL with a different domain, the challenge is called for that domain once, so it is on a per domain basis.

那么为什么挑战只进行一次呢?

So how come the challenge is only made once?

编辑

切换到 NSURLSessionTaskDelegate 和使用 URLSession:task:didReceiveChallenge:completionHandler: 没有区别.

Switching to the NSURLSessionTaskDelegate and using URLSession:task:didReceiveChallenge:completionHandler: makes no difference.

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
{
    completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
}

编辑 相关问题

EDIT 由于目前似乎无法解决此问题,因此我已提交 Apple 错误报告:19072802

EDIT Since there seems to be no way to fix this at the moment, I've filed an Apple bug report: 19072802

推荐答案

您在这里真正想做的是评估每个请求对服务器凭据的信任.

What you're really trying to do here is evaluate the trust of the server's credentials for each request.

技术说明 2232:HTTPS 服务器信任评估 描述了 HTTP 信任进行高层次的评估,并详细介绍如何实施.

Technote 2232: HTTPS Server Trust Evaluation describes HTTP trust evaluation at a high level, and goes into more detail about implementing it.

当您使用 SSL/TLS 连接到主机时,主机会提供一组加密凭据.您的应用程序(可能直接是用户)必须评估这些凭据并决定它们是否可信.

When you connect to a host using SSL/TLS, the host presents a set of cryptographic credentials. Your application (and potentially the user directly) must evaluate those credentials and decide if the can be trusted.

这就像查看某人的驾照或护照,然后决定他们是否是他们所说的那样.

This is like looking at someone's driver's license or passport, and deciding wether they are who they say they are.

想象一下,如果您为某人说的每个单词查看一次他们的身份证明.那会变得乏味!除非这个人改变了,或者他们的身份改变了,否则这没有意义.如果服务器或其凭据发生变化,iOS 将执行信任评估.

Imagine if you looked at someone's identification once for each word they speak. That would get tedius! It would not make sense unless the person changed, or their identification changed. iOS will perform trust evaluation if the server or it's credentials change.

这实际上发生在 HTTP 下的传输(套接字)层,但幸运的是 Foundation 在诸如 NSURLConnectionNSURLSession 之类的 API 中公开了这一点,作为对给予保护空间.如果保护空间(主机)或服务器凭据发生变化,则会发生新的凭据质询.这将反过来促进信任评估.

This actually happens at the transport (socket) layer underneath HTTP, but Foundation thankfully exposes this higher up in APIs such as NSURLConnection and NSURLSession as a credential challenge for a given protection space. If the protection space (the host) or the server credentials change, a new credential challenge occurs. This will in turn prompt trust evaluation.

由于 SSL/TLS 是一种套接字级别的安全措施,真正的工作发生在安全套接字框架 SecureTransport 内的 Foundation URL 加载系统之下.SecureTransport 维护自己的每进程 TLS 会话缓存.这是您必须绕过的层才能获得您正在寻找的行为 - 您需要清除每个连接的 TLS 会话缓存,或强制 SecureTransport 忽略您进程的会话缓存.

Since SSL/TLS is a socket-level security measure, the real work happens far below the Foundation URL loading system inside SecureTransport, the secure socket framework. SecureTransport maintains its own per-process TLS session cache. This is the layer you would have to circumvent to get the behavior you are looking for - you would need to clear the TLS session cache for each connection, or force SecureTransport to disregard the session cache for your process.

技术问答 1727:TLS 会话缓存 描述SecureTransport 会话缓存更详细,并且可能提供一些有趣的选项来绕过 TLS 缓存(即与 DNS 混淆).

Technical Q&A 1727: TLS Session Cache describes the SecureTransport session cache in more detail, and may provide some interesting options for circumventing the TLS cache (i.e. messing with DNS).

目前没有用于清除或修改 SecureTransport TLS 会话缓存的 API.您可以提交请求此功能的雷达.

At this time there is no API for clearing or modifying the SecureTransport TLS session cache. You can file a radar requesting this functionality.

那么为什么挑战只进行一次?"第一次 TLS 信任评估的结果由 SecureTransport 缓存在会话缓存中.

"So how come the challenge is only made once?" The result of the first TLS trust evaluation is cached by SecureTransport in the session cache.

目前没有办法控制这种特定行为.

There is not a way to control that particular behavior at this time.

您可以尝试使用其他一些 HTTPS 库或框架(例如 OpenSSL)、YMMV.

You can try using some other HTTPS library or framework (such as OpenSSL), YMMV.

这篇关于为什么 HTTPS NSURLSession 连接每个域只挑战一次?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆