在iPhone上使用HTTP摘要式身份验证

时间:2009-09-08 10:10:46

标签: iphone authentication session-management http-digest

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

在我看来,iPhone中的“会话”管理对我们的开发人员来说是一个“黑盒子”。是不是我们无法看到框架如何处理/持久化http会话?

如果我只是在这里昏暗,有人会解释如何在iPhone上处理HTTP摘要身份验证吗?

我的基本操作是:

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

这适用于单个请求,但如果我发出其他后续请求,服务器会再次请求授权。服务器已为特定用户持久保存会话,但iPhone由于某种原因未在同一会话中发出请求...因此,服务器必须丢弃身份验证对象并在每次客户端创建一个新对象向安全网址发出请求。

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

如果我们看一下浏览器在这种情况下的表现:

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

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

非常感谢任何帮助。 感谢。

2 个答案:

答案 0 :(得分:3)

首先,是忘记HTTP会话,因为这些会话不与摘要认证活动登录交互(有一种会话信息能力,但它有所不同)。

实际上,使用Digest的一个主要原因是不必仅使用会话来维持登录状态。会话很繁重,可扩展性也很差。

我无法确定你的问题是什么,但我确实知道我会先检查什么,这是正确使用陈旧和正确创建的nonces。

如果用户代理被要求处理相同的随机数,用户代理只能处理身份验证而不会重新查询用户,或者在其他情况下我会稍后再说(更容易按此顺序解释)。

如果您在每个请求中使用相同的随机数,则用户代理将继续将其与来自user / pass的“ha1”一起使用以请求后续资源。这是事先完成的,因此挑战永远不会发生。

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

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

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

我不知道这是否会影响到你,但是确定和发出信号和陈旧的方式肯定是我要看的第一件事。

答案 1 :(得分:1)

我编写了一个带有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"];

现在我的应用程序运行非常顺利,响应速度很快。

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