iOS官方文档翻译iOS文档翻译iOS官方文档

验证挑战和TLS链验证 <- URL会话编程指南

2017-07-12  本文已影响3人  raingu24

NSURLRequest对象经常遇到验证挑战,或者从其他连接的服务器请求证书。当请求遇到验证挑战的时候,NSURLSession类会通知它的委托,以便它们能够相应的执行。

重要:URL加载系统的类一般不调用它们的委托来处理请求挑战,除非服务器的响应包含WWW-Authenticate头部。其他的验证类型,例如代理验证和TLS信任验证,不需要此头部。

决定如何响应一个验证挑战

如果会话任务请求验证,并且没有有效的证书可用,作为请求URL的一部分或者共享的NSURLCredentialStorage,它会创建一个验证挑战。它首先发送URLSession:task:didReceiveChallenge:completionHandler: 到它的任务委托来处理该验证挑战。如果任务委托没有响应这个消息,该任务会发送URLSession:task:didReceiveChallenge:completionHandler:给它的会话委托来处理这个认证挑战。

为了继续连接,委托由三个选项:

为了帮助确定正确的操作过程,传递给该方法的NSURLAuthenticationChallenge实例包含关于触发该验证挑战的信息、对挑战进行的尝试次数、任何之前尝试的证书、请求证书的NSURLProtectionSpace、以及挑战的发送者。

如果验证挑战之前已经有验证但验证失败(例如,如果用户改变了密码或服务器),你可以通过调用验证挑战中的hproposedCredential来获取尝试的证书。然后该委托把这些证书通过弹出对话框显示给用户。

调用验证挑战的previousFailureCount,返回之前验证尝试的总次数,包括了不同验证协议的尝试。该委托可以抱这些信息提供给用户,已确定之前提供的证书是否失败,或者限制验证尝试次数。

响应验证挑战

以下三种方法是对URLSession:didReceiveChallenge:completionHandler: 或 URLSession:task:didReceiveChallenge:completionHandler:委托方法的响应。

提供证书

要想尝试验证,应用程序应该使用验证信息创建NSURLCredential对象,该验证信息应该符合服务器的要求。你可以通过在提供验证挑战的保护空间中调用authenticationMethod确定服务器的验证方法。NSURLCredential支持一些验证方法:

在你创建了NSURLCredential对象之后,使用提供的完成处理程序代码块把这个对象传递给验证挑战的发送者。

无证书连接

如果委托选择不向验证挑战提供证书,它可以尝试无验证的继续连接。把下面值之一传递给完成处理程序代码块:

取消连接

通过给提供的完成处理程序代码块传递NSURLSessionAuthChallengeCancelAuthenticationChallenge,委托也可以选择取消验证挑战。

验证样例

代码清单4-1 展示了,通过创建NSURLCredential实例响应挑战。该实例使用通过应用程序的首选项提供的用户名和密码创建。如果该验证之前失败,它会取消认证挑战并通知用户。

代码清单 4-1 使用URLSession:didReceiveChallenge:completionHandler:委托方法的示例

- (void)URLSession:(NSURLSession *)session

didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge

  completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * __nullable credential))completionHandler

{

    if ([challenge previousFailureCount] == 0) {

        NSURLCredential *newCredential = [NSURLCredential credentialWithUser:[self preferencesName]

                                                                    password:[self preferencesPassword]

                                                                 persistence:NSURLCredentialPersistenceNone];

        completionHandler(NSURLSessionAuthChallengeUseCredential, newCredential);

    } else {

        // Inform the user that the user name and password are incorrect

        completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);

    }

}
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {

    guard challenge.previousFailureCount == 0 else {

        challenge.sender?.cancel(challenge)

        // Inform the user that the user name and password are incorrect

        completionHandler(.cancelAuthenticationChallenge, nil)

        return

    }

    

    let proposedCredential = URLCredential(user: self.preferencesName, password: self.preferencesPassword, persistence: .none)

    completionHandler(.useCredential, proposedCredential)

}

如果验证挑战没有被会话或任务委托处理,且证书不可用或使用它们验证失败,continueWithoutCredentialForAuthenticationChallenge消息会通过底层的实现发送。

执行自定义的TLS链验证

在NSURL系列API中,TLS链验证通过app验证委托方法处理,而不是提供验证用户(或app)的证书给服务器。App会在TLS握手期间检查服务器提供的证书,然后告诉URL加载系统是否应该接受或拒绝这些证书。

如果你需要以非标准的方式执行链验证(例如,为测试接收一个特定的自签名证书),app必须实现URLSession:didReceiveChallenge:completionHandler: 或 URLSession:task:didReceiveChallenge:completionHandler:委托方法。如果两者都实现,则会话级别的方法负责处理验证。

在你的验证处理委托方法中,你应该检查挑战保护空间是否有NSURLAuthenticationMethodServerTrust的验证类型,如果有,从保护空间获取serverTrust信息。

上一篇下一篇

猜你喜欢

热点阅读