我有一个与使用 HTTP 摘要身份验证的服务器进行通信的应用程序。

在我看来,iPhone 中的“会话”管理对于我们开发人员来说是相当“黑匣子”。我们真的看不到框架如何处理/持久化 http 会话吗?

如果我只是在这里昏昏欲睡,有人愿意解释一下如何在 iPhone 上处理 HTTP 摘要身份验证吗?

我的基本流程是:

  • 向安全 URL 发出请求
  • 服务器发送 401
  • 客户端创建并保留凭证,并将其传回服务器
  • 服务器验证凭据,如果已验证则完成请求,如果未验证则发送另一个 401。
  • 发出后续请求以保护 url
  • 服务器再次请求授权......

这适用于单个请求,但如果我发出额外的后续请求,服务器将再次请求授权。服务器已为特定用户保留了一个会话,但由于某种原因 iPhone 没有在同一会话中发出请求......因此,每次客户端向安全 URL 发出请求时,服务器都必须丢弃身份验证对象并创建一个新对象。

我确信这不是正确的行为。

如果我们看看浏览器在这种情况下的行为:

  • 浏览器从安全 URL 请求数据
  • 服务器发送401
  • 浏览器提示用户输入凭据,保留该凭据,然后将其传递给服务器
  • 服务器验证凭据,如果通过验证则返回数据,如果没有验证则发送另一个 401。
  • 由于浏览器管理会话,因此后续对安全 URL 发出的请求不会提示输入凭据。

我正在创建 NSURLCredential 并将其保留在 NSURLCrendtialStorage 中。然后,当应用程序收到“didReceiveAuthenticationChallenge”时,我从存储中检索凭据并将其传回,如果凭据不存在(在第一个请求时),则创建该凭据。

任何帮助将不胜感激。谢谢。

有帮助吗?

解决方案

首先,忘记 HTTP 会话,因为它们不与摘要式身份验证主动登录交互(有一种会话信息功能,但它是不同的)。

事实上,使用 Digest 的主要原因之一是不必仅使用会话来维持登录状态。会话量很大并且会损害可扩展性。

我无法确定您的问题是什么,但我确实知道我首先要检查的内容是正确使用过时的内容和正确创建随机数。

如果用户代理被要求处理相同的随机数,则用户代理只能处理身份验证,而无需重新查询用户,或者在另一种情况下,我将在稍后介绍(按此顺序更容易解释)。

如果您在每个请求中使用相同的随机数,则用户代理将继续使用它以及用户/通行证中的“ha1”来请求后续资源。这是预先完成的,因此挑战永远不会发生。

当然,使用相同的随机数会带来不安全因素,因为重放攻击对于任何可以嗅探流量的人来说都变得微不足道。随机数必须定期更改。

因此,如果您收到来自用户代理的请求,该请求具有无效的授权标头,但其无效的原因是随机数错误(它使用的是过期的随机数),那么在您的挑战中包括“stale=true”(默认为错误的)。这会通知用户代理您拒绝的原因是随机数已过时(当然其他信息也可能是错误的,但这并不重要,因为您不会让它以任何方式发挥作用)。

收到这样的 stale=true 时,用户代理将知道它没有被授权,但不会重新查询用户(或者如果它是无 UI 组件,则抛出异常),而是使用新的随机数重试旧标准。

我无法判断这些是否会影响您,但随机数和过时性的确定和表示方式肯定是我首先要考虑的事情。

其他提示

我已经编写了一个带有 HTTP 身份验证的 iPhone 应用程序,并且经历了您所描述的情况。(我的应用程序使用基本身份验证而不是摘要身份验证,但这在这里没有太大区别。)

问题原因出在iPhone端。如果 iPhone 未发送 HTTP 请求标头中的凭据,服务器需要回答 401。事实上,即使一旦凭证存储在凭证存储中,它也很容易做到。

这种奇怪的行为对应用程序的速度产生了严重影响,因为每个请求都会导致到服务器的两次往返,而不是一次(第一个状态为 401,第二个状态为 200)。

我通过手动设置 HTTP 请求标头中的凭据解决了这个问题:

NSString* credentials = [NSString stringWithFormat: @"%@:%@", usr, pwd];
const char* credentialsChars = [credentials cStringUsingEncoding: NSUTF8StringEncoding];
credentials = [CommunicationUtil stringBase64WithData: (const UInt8*) credentialsChars length: strlen(credentialsChars)];
NSString* authorizationHeader = [NSString stringWithFormat: @"Basic %@", credentials];

NSMutableURLRequest* request =
    [[NSMutableURLRequest alloc] initWithURL: url 
        cachePolicy: NSURLRequestReloadIgnoringLocalCacheData
        timeoutInterval: 15];

    [request setValue: authorizationHeader forHTTPHeaderField: @"Authorization"];

现在我的应用程序运行非常顺利并且响应非常灵敏。

摘要身份验证的解决方案看起来略有不同。但你会明白的。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top