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

发布于 2024-08-03 17:21:59 字数 905 浏览 11 评论 0原文

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

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

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

我的基本流程是:

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

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

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

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

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

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

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

I have an app that communicates with a server that uses HTTP Digest authentication.

It seems to me that the 'session' management within the iPhone is pretty "black box" to us developers. Is it true that we can't see how the framework handles / persists http sessions?

If I'm just being dim here, would someone care to explain how to probably handle HTTP Digest authentication on the iPhone?

My basic run through is:

  • Make a request to a secured url
  • Server sends a 401
  • client creates and persists a credential, and passes it back to the server
  • server verifies credential, completes request if verified, sends another 401 if not.
  • make a subsequent request to secure url
  • server requests authorisation again........

This works for single requests, but if I make additional, subsequent requests, the server requests authorisation again. The server has persisted a session for the particular user, but the iPhone isn't making a request within the same session for some reason... Therefore, the server has to throw out the authentication object and create a new one each time the client makes a request to a secured url.

I'm sure this isn't correct behaviour.

If we look at how a browser behaves in this situation:

  • Browser requests data from secure url
  • server sends 401
  • browser prompts user for credential, persists it, passes it to server
  • server verifies credential, returning data if verified, sends another 401 if not.
  • subsequent requests made to secure urls are not prompted for credentials because the browser manages the session.

I'm creating the NSURLCredential and persisting it within the NSURLCrendtialStorage.
Then when the app receives the 'didReceiveAuthenticationChallenge' I retrieve the credential from the storage and pass it back, creating the credential if it doesn't exist (on the first request).

Any help would be greatly appreciated.
Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

总以为 2024-08-10 17:21:59

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

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

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

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

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

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

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

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

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

First thing, is to forget about HTTP sessions, as these do not interact with Digest authentication active log-ins (there is a sort of session info ability, but it's different).

Indeed, one of the main reasons for using Digest, is to not have to use sessions just to maintain a logged-in state. Sessions are heavy and hurt scalability.

I couldn't say for sure what your issue is, but I do know what I would check on first, which is correct use of stale and correct creation of nonces.

User-agents can only handle authentication without requerying the user if they are asked to handle the same nonce, or in another case I will come to later (easier to explain it in this order).

If you have the same nonce used in each request, then the user-agent will continue to use it along with the "ha1" from the user/pass to request subsequent resources. This is done preëmptively, so the challenge never happens.

Of course, using the same nonce introduces an element of insecurity, as replay attacks become trivial to anyone that can sniff the traffic. Nonces will have to change on a regular basis.

Hence, if you receive a request from a user-agent with an invalid Authorization header, but the reason it is invalid is that the nonce is wrong (it's using an expired one) then in your challenge include "stale=true" (defaults to false). This informs the user-agent that your reason for rejecting is the nonce is outdated (of course the other information may also be wrong, but that doesn't matter as you aren't going to let it play either way).

On receiving such a stale=true the user-agent will know that it isn't authorised, but instead of requerying the user (or throwing an exception if it's a UI-less component) will retry the old criteria with the new nonce.

I can't tell if any of this is what's affecting you, but the way nonces and staleness are determined and signalled is certainly the first thing I'd look at.

沧桑㈠ 2024-08-10 17:21:59

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

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

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

I've written an iPhone app with HTTP authentication and experienced what you describe. (My application uses basic authentication instead of digest authentication, but that doesn't make a big difference here.)

The cause of the problem is on the iPhone side. The server is required to answer with 401 if the iPhone doesn't send the credentials in the HTTP request header. And in fact it doesn't even though it easily could once the credential is stored in the credential storage.

This strange behavior had a severe effect on the speed of the application since every request caused two round-trips to the server instead of one (the first one with status 401, the second with 200).

I've solved it by manually setting the credentials in the HTTP request header:

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"];

Now my application works very smoothly and is very responsive.

The solution will look slightly different for digest authentication. But you'll get the idea.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文