我有自定义证书验证的应用程序。代码很简单:
- (void) URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition,
NSURLCredential *credential))completionHandler
{
NSString * authenticationMethod = challenge.protectionSpace.authenticationMethod;
CSHTTPDownoadTaskProxy *proxyTask = [self streamedDataTaskForHttpTask: task]; // get custom information about task
if ([authenticationMethod isEqualToString: NSURLAuthenticationMethodServerTrust]) {
if (!proxyTask) {
completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, nil);
LOG_UNEXPECTED_TASK(task);
return;
}
[self validateCertificate: challenge.protectionSpace withCompletionHandler: completionHandler];
} else if ([authenticationMethod isEqualToString: NSURLAuthenticationMethodHTTPBasic] {
… … …
}
}
- (void) validateCertificate: (NSURLProtectionSpace *)protectionSpace
withCompletionHandler: (void (^)(NSURLSessionAuthChallengeDisposition disposition,
NSURLCredential *credential))completionHandler {
// some logic
… … …
completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, nil);
}
现在,当证书被拒绝时,通常一切都按预期工作,证书被拒绝并报告HTTP请求的错误。
对于某些服务器,即使调用了completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, nil);
,也会成功处理并完成请求。
NSURLSessionAuthChallengeRejectProtectionSpace
文档说:
拒绝此挑战,并调用身份验证委托方法 再次使用下一个身份验证保护空间。提供的 凭证参数被忽略。
这有点令人困惑,它意味着什么"下一个身份验证保护空间"?
这个API还包括密码保护空间,我理解,如果服务有多种身份验证方式,例如:Negotiate,Diget,Basic,NSURLSession
首先获得最好的认可,它会被拒绝通知其他可能性或者请求失败。
但是我的委托仅针对此身份验证方法NSURLAuthenticationMethodServerTrust
调用一次!
对于大多数情况,当我使用此值时,会报告预期错误(无效证书):
错误域= NSURLErrorDomain代码= -1202"此证书 服务器无效。您可能正在连接到的服务器 假装是“10.133.32.55”,可以保密 有风险的信息。"
对于其他情况(日志显示已使用正确值调用完成处理程序)HTTP请求已处理并成功完成(对于不同客户端计算机上的某些服务器,它会发生)。
其他人是否遇到类似的问题?
我可以使用NSURLSessionAuthChallengeCancelAuthenticationChallenge
做一些讨厌的解决方法。此值报告该请求是"已取消"所以我必须生成自己的错误。
我不喜欢这种方法,并且更愿意找出为什么NSURLSessionAuthChallengeRejectProtectionSpace
有时无效的原因。
好的,我有一些额外的线索。问题仅出现在要求客户身份证书的服务器上。 如果不需要客户端身份,则接受证书验证(证书在请求时被拒绝),如果要求客户端身份并且可用,则忽略服务器证书验证结果。
在找到精确答案之后,看起来配置测试服务器的人对于具有客户端身份的服务器更适合这样做会导致这种副作用。
答案 0 :(得分:2)
NSURLSessionAuthChallengeRejectProtectionSpace
的目的是告诉操作系统您无法对特定的身份验证类型执行任何操作。例如,如果服务器表示愿意接受客户端证书,基本身份验证(用户名/密码)或摘要身份验证(基本上使用用户名/密码作为密钥签署请求),那么NSURLSession
会问你一次用于其中一种方法。
如果会话要求您提供客户端证书,并且您拥有的是用户名和密码,则通过使用NSURLSessionAuthChallengeRejectProtectionSpace
调用延续块来拒绝客户端证书身份验证方法,然后会话将要求您提供用户名和密码。
IMO,将NSURLSessionAuthChallengeRejectProtectionSpace
与服务器信任身份验证结合使用并没有多大意义,因为TLS无法替代连接是否可信。在实践中,我认为这相当于调用NSURLSessionAuthChallengePerformDefaultHandling
,这意味着如果证书是可信的,它将被接受,否则将被拒绝。但是,如果这是期望的行为,则应明确使用NSURLSessionAuthChallengePerformDefaultHandling
(如果要取消请求,则应NSURLSessionAuthChallengeCancelAuthenticationChallenge
。)
可能是在客户端证书存在的情况下拒绝请求会导致服务器的证书被忽略,在这种情况下,这可能是一个错误,您应该将其归档。但这样做的原因可能是因为在发送客户端证书时需要接受服务器的证书,并且您告诉它跳过服务器验证并向您发送下一个方法(客户端证书)。因此,我非常确定事情表现得很奇怪。
另外,你需要一个决赛"否则"在那里处理未知的保护空间。机会是,其他情况应该使用NSURLSessionAuthChallengePerformDefaultHandling
。如果你不这样做,那么当你得到一个未知的保护空间时,连接将永远保持打开状态,永远不会前进或被取消,因为没有任何东西会调用延续块。