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

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

问题描述

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



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



以下是一个示例:

   - (IBAction)reload:(id)sender {
NSURLSession * session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration] delegate:self delegateQueue:nil];
//请注意,https://www.example.com不是我真正连接到的网站。
NSURL * URL = [NSURL URLWithString:@https://www.example.com];
NSMutableURLRequest * URLRequest = [NSMutableURLRequest requestWithURL:URL];

[[session dataTaskWithRequest:URLRequest
completionHandler:^(NSData * data,NSURLResponse * response,NSError * error){
//此处收到响应。
}] resume];
}

#pragma NSURLSessionDelegate

- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void NSURLSessionAuthChallengeDisposition disposition,NSURLCredential * credential))completionHandler
{
//仅对第一个请求调用,后续请求不调用此方法。
completionHandler(NSURLSessionAuthChallengeUseCredential,[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
}

由于我想要URLCredential是每个会话或每个任务, NSURLCredential 我传递给 completionHandler ,我发现它有一个持久性 NSURLCredentialPersistenceForSession (这是不可变的),这似乎是正确的。



我也检查了 [NSURLCredentialStorage allCredentials] ,它是空的,所以它不缓存凭据。 >

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

那么挑战怎么才能做呢?



EDIT



切换到 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]);
}

EDIT 相关问题



编辑由于似乎无法修复现在,我提交了一个Apple Bug报告:19072802

解决方案

你真正想做的是评估每个请求的服务器凭据的信任。



Technote 2232:HTTPS服务器信任评估在高级别描述了HTTP信任评估,并详细介绍了它的实现。



使用SSL / TLS连接到主机时,主机会显示一组加密凭证。您的应用程式(以及潜在的使用者)必须评估这些凭证,并决定是否可信。



这就像是查看某人的驾驶执照或护照,他们是他们说他们是谁。



想象一下,如果你看着某人的识别一次他们说的每个字。这会得到tedius!除非人改变,或者他们的身份改变了,否则没有意义。如果服务器或其凭据发生更改,iOS将执行信任评估。



这实际上发生在HTTP下的传输(套接字)层,但Foundation感谢地在API例如 NSURLConnection NSURLSession 作为给定保护空间的凭据质询。如果保护空间(主机)或服务器凭证更改,则会出现新的凭据质询。



由于SSL / TLS是一个套接字级的安全措施,真正的工作发生在远低于$ URL内的Foundation URL加载系统$ c> SecureTransport ,安全套接字框架。 SecureTransport 维护自己的每进程TLS会话高速缓存。这是您必须绕过以获取您正在寻找的行为的层 - 您需要清除每个连接的TLS会话缓存,或强制 SecureTransport 忽略会话缓存。



技术Q& A 1727:TLS会话缓存更详细地描述了 SecureTransport 会话缓存,并且可以提供一些有趣的选项来绕过TLS缓存(即, )。



此时没有用于清除或修改 SecureTransport TLS会话缓存的API。您可以提出要求此功能的雷达。



TL; DR;




第一次TLS信任评估的结果由会话缓存中的 SecureTransport 缓存。



目前没有办法控制此特定行为。



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


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.

Here's an example:

- (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]);
}

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.

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

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?

EDIT

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 related question

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.

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

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.

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.

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.

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.

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).

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

TL;DR;

"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.

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

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

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