ios - 在 ServerTrust 之后不调用 'didReceiveChallenge' 进行 HttpBasic 身份验证

标签 ios nsurlconnection nsurlsession

我正在将 iOS 应用程序从 NSURLConnection 转换为 NSURLSession。

服务器使用 https(由公认的 CA 签名的证书)和基本身份验证进行交互。

我没有使用完成 block 来返回数据,而是使用自定义委托(delegate)。我在别处看到,使用自定义委托(delegate)意味着我应该响应 AuthenticationChallenges 而不是依赖 CredentialStorage(这也行不通,但那是另一个问题)。

我的问题是,对 ServerTrust 进行了一次质询,但对 HttpBasic 身份验证不会再次调用。所以,我的 session 超时了。

我已经尝试为“defaultSession dataTaskWithRequest”使用完成 block 而不是自定义委托(delegate),只是想看看我是否可以通过这一点,但这没有什么区别。我还尝试将 CredentialStorage 用于 HttpBasic 凭据,但如上所述,我并不高兴。

这让我难住了。有什么想法吗?

(void)URLSession:(NSURLSession *)connection
//    task:(NSURLSessionTask *)task
    didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
    completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * __nullable credential))completionHandler
{
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
    {
#if 1 && defined(DEBUG)
        NSLog (@"didReceiveChallenge: Using SSL");
#endif // DEBUG

        if ([challenge.protectionSpace.host isEqualToString:HOST])
        {
#if 1 && defined(DEBUG)
            NSLog (@"didReceiveChallenge: Using Protection Space Host - %@", HOST);
#endif // DEBUG

            [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
        }
        else
        {
            [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
        }
    }
    else

    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodHTTPBasic] ||
        [challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodHTTPDigest])
    {
#if 1 && defined(DEBUG)
        NSLog (@"didReceiveChallenge: (Basic / Digest) #%ld - user: %@, password: %@",
               (long)[challenge previousFailureCount],  USERNAME, PASSWORD);

#endif // DEBUG

        if ([challenge previousFailureCount] == 0)
        {
#if 1 && defined(DEBUG)
            NSLog (@"didReceiveChallenge: previousFailureCount == 0");
#endif // DEBUG

            NSURLCredential *newCredential;

            newCredential = [NSURLCredential credentialWithUser:USERNAME
                            password:PASSWORD
                            persistence:NSURLCredentialPersistenceForSession];

            [[challenge sender] useCredential:newCredential forAuthenticationChallenge:challenge];

        }
        else
        {
            [[challenge sender] cancelAuthenticationChallenge:challenge];

            // inform the user that the user name and password
            // in the preferences are incorrect

#if 1 && defined(DEBUG)
            NSLog (@"didReceiveChallenge: Failed Authentication");
#endif // DEBUG

            // ...error will be handled by connection didFailWithError
        }
    }
#ifdef DEBUG
    else
    {
        NSLog(@"didReceiveChallenge: Not handled!");
    }

#endif // DEBUG
}

最佳答案

排名不分先后:

  • 您实际上已经为相关的特定主机完全禁用了 TLS,因为您没有以任何有意义的方式检查证书,而只是检查它是否提供了与给定主机名匹配的证书。这是非常非常危险的。相反,您需要对证书执行一些自定义验证(例如,检查 key 是否与固定 key 匹配或检查它是否由已知可信的内部证书签名),然后仅在验证时执行您正在执行的操作.
  • 通过指定您不想让服务器提供其证书,您(我认为)有效地完全破坏了所有其他主机的 TLS。在这种情况下,您应该要求进行默认处理。
  • 对于任何其他挑战类型,您的方法是忽略挑战,这意味着连接将永远挂起,永远不会取得进展。在这些情况下,您也应该要求进行默认处理。否则,当(而不是如果)您被要求提供客户端证书时,您的连接将似乎挂起并最终会超时。
  • 您对实际通知的处理有误。您应该永远不要使用 NSURLSession 调用质询发送者的方法。您必须调用完成方法。否则, session 将继续等待您调用它,直到请求超时。

我不确定代码中是否还有其他错误,但所有这三个错误都可能导致严重的不当行为,其中一个是主要的安全漏洞。首先解决这些问题,如果仍然不起作用,请添加更多评论。 :-)

关于ios - 在 ServerTrust 之后不调用 'didReceiveChallenge' 进行 HttpBasic 身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41417558/

相关文章:

iphone - 将 helpshift 添加到应用程序导致 UIApplicationInvalidInterfaceOrientation 异常

android - 需要访问联系人的权限才能将应用程序中的联系人信息保存到 native 联系人中吗?

objective-c - 等待 NSURLConnection

ios - 如果应用程序被杀死,NSURLSessionTask 会发生什么

ios - 在第一个 View Controller 中完成某些操作后,在第二个 View Controller 中重新加载数据

iOS : Blocked a frame with origin "https://www.youtube.com" from accessing a frame with origin

IOS 如何使用 RESTFUL API 从 Web 服务中检索数据

ios - 停止 NSOperationQueue

swift - 返回从 HTTP 请求中检索到的值的方法

ios - NSURLSession 不返回 http/https 的数据