公共客户端上的客户端身份验证 [英] Client authentication on Public Client

查看:83
本文介绍了公共客户端上的客户端身份验证的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在学习 OAuth2.0 的过程中,我终于找到了这 2 个参考文献:RFC6749 第 2.3 节RFC6749 第 10.1 节

如果我错了,请纠正我:

<块引用>

可以使用未注册的客户端,但您必须自己管理它们,存在安全风险.

  • 我应该如何管理它们?

一些更具体的问题:

  1. 本机应用程序(确实是公共客户端)根据定义,无法安全地存储其凭据(client_id + secret).它是未注册的客户端吗?如果我无法使用机密对其进行验证/验证,我还应该怎么做?
  2. 客户端注册≠端点注册:首先是关于注册客户端凭据(client_id + secret);第二个关于注册客户端重定向端点.重定向端点注册是否足以授予客户端的真实性?
  3. 客户凭据授予是否使用相同的 用于客户端注册的凭据(client_id + secret)?

我想你可以通过解释什么来回答我这一段(RFC6749 第 10.1 节) 的意思.

请给我一些关于如何实现授权服务器和资源服务器之间交互的参考和实例.

谢谢

解决方案

tl;dr:

  1. 本地客户端无法使用 client_idclient_secret 进行身份验证.如果您需要对客户端进行身份验证,则必须实施不将共享机密委托给客户端(或让最终用户参与客户端身份验证讨论)的身份验证方案.根据您应用的安全模型,您可能不需要对客户端进行身份验证.
  2. 重定向端点通常不足以对客户端进行身份验证(尽管存在例外情况).
  3. 客户端凭据"授予类型可以使用授权服务器支持的任何客户端身份验证机制,包括在客户端注册时提供的凭据.

我读到的要点是,您可以信任机密客户端的 client_id(读作:用户名")和 client_secret(读作:密码")使用您的服务对它们进行身份验证.第三方应用程序永远不会[1] 使用该客户端的凭据来代表自己,因为它们被合理地假定为安全存储,远离窥探.

然而,公共客户端无法做出这样的保证——无论是基于浏览器的应用程序还是本机桌面应用程序,客户端的 id 和机密都被分发到全世界.可以合理地假设此类应用程序最终会落入能够深入客户端并提取 id 和机密的熟练开发人员和黑客手中.为此,第 10.1 节明确指出:

授权服务器不得发布客户端密码或其他本地应用程序或基于用户代理的客户端凭据用于客户端身份验证的应用程序客户端.

好的.因此公共客户端无法通过密码进行身份验证.不过……

授权服务器可能会发出客户端密码或其他本地应用程序特定安装的凭据特定设备上的客户端.

此异常有效,因为它将客户端的身份验证与特定设备联系起来,这意味着即使有人带走了客户端的秘密,他们也无法重用它.然而,此例外隐含着特定设备……在特定设备上的特定安装"必须是唯一可识别的,难以欺骗,并且是该客户端身份验证过程的组成部分.

并非每个本机应用程序都能满足这些标准,基于浏览器的应用程序当然不能,因为在它运行的环境中没有任何可唯一识别或难以欺骗的东西.这导致了几种选择 - 您可以将客户端视为未经身份验证,或者您可以提出更合适的身份验证机制.

身份验证舞蹈的关键是一个共享秘密——只有授权服务器和身份验证客户端知道的东西.对于公共客户,客户本身没有任何秘密.幸运的是,有很多选择,而且我不只是在谈论 RFID 密钥卡和生物识别技术(尽管这些都是完全可以接受的).

作为一个思想实验,让我们考虑一个基于浏览器的客户端.我们可以合理地假设一些事情:它在浏览器中运行,从特定域提供服务,并且该域由客户端的作者控制.身份验证服务器应该已经有一个客户端重定向 URI,所以我们已经有了一些东西,但正如规范所说:

一个有效的重定向 URI 不足以验证客户端的请求资源所有者授权时的身份,但可以用于防止向假冒客户提供凭据获得资源所有者授权后.

所以重定向 URI 是我们应该检查的东西,但不是我们可以信任的东西,这在很大程度上是因为域可能被欺骗.但是服务器本身不能,所以我们可以尝试询问域一些只有客户端域的服务器才知道的东西.执行此操作的最简单方法是身份验证服务器需要第二个(私有")URI,位于与客户端相同的域上,客户端的机密将在该域中托管.当客户端应用程序发出授权请求时,服务器然后签入"第二个 URI相对于客户端报告的主机名,并查找共享秘密(应该只向授权公开服务器的 IP 地址)以对客户端进行身份验证.

当然,这不是一个完美的解决方案.它并不适用于每个应用程序,很容易出错,并且可能需要大量工作来实现.存在许多潜在的身份验证机制(高度具体和高度通用),任何不将私有数据委托给客户端应用程序的机制都适用于这个问题空间.

我们的另一个选择是不实施进一步的身份验证,并将客户端视为未经身份验证.这与未注册的客户端明显不同,但区别很微妙.未注册的客户端是身份未知的客户端.未经身份验证的客户端是其身份已知但不受信任的客户端.这两种类型的客户端的安全含义是相同的:不应将私有数据委托给它们.然而,授权服务器是否选择将这两种情况一视同仁,似乎由实现者决定.例如,API 拒绝来自未注册客户端的所有连接,并向任何注册客户端提供公共只读内容(即使不验证客户端的身份)可能是有意义的.>

然而,实用主义可能会胜出——未经身份验证的客户端与您在浏览器无法验证网站 SSL 证书的真实性时偶尔会看到的 SSL错误"从根本上没有什么不同.浏览器将立即拒绝进一步处理并准确报告原因,但允许用户通过担保服务器的身份自行承担风险.类似的工作流程可能适用于许多 OAuth2 应用程序.

为什么验证客户的身份很重要?如果不这样做,信任链就会被打破.您的应用程序的用户信任您的应用程序.授权工作流确定您的用户也信任客户端,因此您的应用程序应该信任客户端.在不验证客户端身份的情况下,另一个客户端可以出现并承担受信任客户端的角色,并拥有其所有安全权限.与客户端身份验证相关的一切都有助于防止这种信任遭到破坏.

希望这有帮助!

[1]:服务器入侵,即您的应用程序的源代码落入恶意手中,是一个例外,并且针对这种情况还有其他内置保护措施.话虽如此,规范还特别指出,简单的用户名/密码组合并不是最安全的选择:

鼓励授权服务器考虑更强身份验证意味着比客户端密码.

Studying OAuth2.0 I finally found these 2 refs: RFC6749 section 2.3, RFC6749 section 10.1

Correct me if I'm wrong:

It's possible to use unregistered clients, but you have to manage them yourself with security risks.

  • How should I manage them?

Some more specific questions:

  1. A Native Application (a Public Client indeed) is not able, by definition, to safely store its credentials (client_id + secret). Is it an unregistered client? If I can't verifiy/authenticate it using a secret, what else should I do?
  2. client registration ≠ endpoint registration: the first is about registering Client Credentials (client_id + secret); the second about registering Client Redirection Endpoints. Is the Redirection Endpoint registration sufficient to grant the authenticity of the Client?
  3. Does Client Credential Grant use the same credentials (client_id + secret) for client registration?

I think you could answer me by explaining what does this paragraph (RFC6749 section 10.1) mean.

Please give me some references and practical examples on how to implement the interaction between the authorization server and the resource server.

Thanks

解决方案

tl;dr:

  1. Native clients cannot be authenticated with client_id and client_secret. If you need to authenticate the client, you'll have to implement an authentication scheme that doesn't entrust the shared secret to the client (or involve the end-user in the client authentication discussion). Depending on your application's security model, you might not need to authenticate the client.
  2. The redirection endpoint is not generally sufficient to authenticate the client (though exceptions exist).
  3. The "client credential" grant type may use any client authentication mechanism supported by the authorization server, including the credentials given out at client registration.

The gist, as I read it, is that you can trust a confidential client's client_id (read: "username") and client_secret (read: "password") to authenticate them with your service. There is no[1] chance that a third-party application will ever represent itself with that client's credentials, because they are reasonably assumed to be stored safely away from prying eyes.

A public client, however, can make no such guarantee – whether a browser-based application or a native desktop application, the client's id and secret are distributed to the world at large. It's quite reasonable to assume that such applications will end up in the hands of skilled developers and hackers who can dig into the client and extract the id and secret. For this reason, Section 10.1 explicitly states that:

The authorization server MUST NOT issue client passwords or other
client credentials to native application or user-agent-based
application clients for the purpose of client authentication.

Okay. So public clients cannot be authenticated by password. However…

The authorization server MAY issue a client password or other
credentials for a specific installation of a native application
client on a specific device.

This exception works because it ties the authentication of the client to a specific device, meaning that even if someone walked away with the client's secret, they couldn't reuse it. Implicit in this exception, however, is that the "specific installation … on a specific device" must be uniquely identifiable, difficult to spoof, and integral to the authentication process for that client.

Not every native application can meet those criteria, and a browser-based application certainly cannot, since there's nothing uniquely identifiable or difficult to spoof in the environment in which it runs. This leads to a couple of options – you can treat the client as unauthenticated, or you can come up with a more appropriate authentication mechanism.

The key to the authentication dance is a shared secret – something that's known only to the authorization server and the authenticating client. For public clients, nothing in the client itself is secret. Thankfully, there are options, and I'm not just talking about RFID key fobs and biometrics (though those would be completely acceptable).

As a thought experiment, let's consider a browser-based client. We can reasonably assume a few things about it: it's running in a browser, it's served from a particular domain, and that domain is controlled by the client's authors. The authentication server should already have a Client Redirection URI, so we've got something there, but as the spec calls out:

A valid redirection URI is not sufficient to verify the client's
identity when asking for resource owner authorization but can be
used to prevent delivering credentials to a counterfeit client
after obtaining resource owner authorization.

So the redirection URI is something we should check, but isn't something we can trust, in large part because the domain could be spoofed. But the server itself can't be, so we could try to ask the domain something that only the client's domain's server would know. The simplest way to do this would be for the authentication server to require a second ("private") URI, on the same domain as the client, where the client's secret will be hosted. When the client application makes an authorization request, the server then "checks in" against that second URI relative to the client's reported hostname, and looks for the shared secret (which should only ever be disclosed to the authorization server's IP address) to authenticate the client.

Of course, this is not a perfect solution. It doesn't work for every application, it's easy to get wrong, and it's potentially a lot of work to implement. Many potential authentication mechanisms (both highly specific and highly general) exist, and any one which does not entrust the client application with private data would be suitable for this problem space.

The other option we have is to implement no further authentication, and treat the client as unauthenticated. This is notably not the same thing as an unregistered client, but the difference is subtle. An unregistered client is a client whose identity is unknown. An unauthenticated client is a client whose identity is known, but untrusted. The security implication for both types of clients is the same: neither should be entrusted with private data. Whether the authorization server chooses to treat these two cases the same, however, seems to be left up to the implementer. It may make sense, for example, for an API to refuse all connections from an unregistered client, and to serve public read-only content to any registered client (even without verifying the client's identity).

Pragmatism, however, may yet win out – an unauthenticated client is fundamentally no different than the SSL "errors" you'll occasionally see when your browser cannot verify the authenticity of the site's SSL certificate. Browsers will immediately refuse to proceed any further and report exactly why, but users are allowed to accept the risk themselves by vouching for the identity of the server. A similar workflow may make sense for many OAuth2 applications.

Why is it important to verify the client's identity, anyway? Without doing so, the chain of trust is broken. Your application's users trust your application. The authorization workflow establishes that your users also trust the client, so your application should trust the client. Without validating client identity, another client can come along and assume the role of the trusted client, with all of the security rights thereof. Everything about client authentication serves to prevent that breach of trust.

Hope this helped!

[1]: Server compromises, where the source code of your application falls into malicious hands, are an exception to this, and there are other safeguards built-in for that case. Having said that, the spec also specifically calls out that a simple username/password combination isn't the safest option:

The authorization server is encouraged to consider stronger
authentication means than a client password.

这篇关于公共客户端上的客户端身份验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆