OAuth2 - 资源所有者密码凭证授予

信息安全 验证 oauth
2021-09-05 16:53:05

OAuth2 规范在此处描述了资源所有者密码凭据授予类型和授权流程我知道只有“受信任的”客户端应用程序才能使用此授权,例如后端 API 的“官方”iPhone 或 Android 客户端应用程序。

我的问题是:我如何保证来自声称是此客户端应用程序的来源的请求可以信任?例如:

  • 我已经在我的 OAuth2 服务器上注册了我的 android 应用程序,其 client_idandroid_app可以访问授予类型password(即资源所有者密码凭据)。

  • 由于 Android 应用程序是一个客户端应用程序,因此我假设不信任将客户端秘密“保密”,因此没有为其分配一个。应用程序配置包含 client_id 和 grant_type 以及身份验证端点。

  • 用户反编译/解压缩/去混淆我的应用程序并找到 client_id 和端点

是什么阻止他们客户端使用客户端 ID 向该端点发出身份验证请求?我会考虑为客户端分配一个 client_secret,但这似乎并不能解决问题,因为用户可以在应用程序中找到它。

3个回答

这真的是两个问题。


我如何保证来自声称是此客户端应用程序的来源的请求是可信的?

你不能。规范

资源所有者密码凭证授予类型适用于资源所有者与客户端具有信任关系的情况 [...]

资源所有者(又名用户)必须决定他是否信任客户端,而不是授权服务器。如果用户决定信任第三方应用程序以至于他输入了他的纯密码,那么您无法自动检测第三方应用程序是否值得信赖。


是什么阻止他们客户端使用客户端 ID 向该端点发出身份验证请求?我会考虑为客户端分配一个 client_secret,但这似乎并不能解决问题,因为用户可以在应用程序中找到它。

OAuth2 区分机密客户端和公共客户端机密客户端“能够维护其凭据的机密性”,例如在服务器端访问另一个的 Web 应用程序。

本机应用程序(如 Android 应用程序)被明确提及为公共客户端:

本机应用程序是在资源所有者使用的设备上安装和执行的公共客户端。资源所有者可以访问协议数据和凭证。假设可以提取应用程序中包含的任何客户端身份验证凭据。[...]

因此,在大多数用例中,客户端密码不会为原生应用程序增加安全性。

我如何保证来自声称是此客户端应用程序的来源的请求是可信的?

你不能。

引用另一个 SO答案

问题是,在移动设备中,应用程序已经是受信任的,一旦用户安装了他选择信任的应用程序 [...] 最终我认为不可能完全保护用户免受应用程序的影响。 '已经决定通过安装来信任它。

是什么阻止他们客户端使用客户端 ID 向该端点发出身份验证请求?

没有什么。

您只能专注于保护用户的用户名/密码,例如:

  • 不要将它们存储在您的应用程序中。
  • 教育您的用户,明确说明从何处获取您的官方应用程序以及为什么他们不应该信任任何其他要求他们提供凭据的应用程序。

一点解释:

为了访问资源,应用程序需要获取访问令牌(最终是可选的刷新令牌)。

要获取访问令牌,必须将包含用户名和密码的第一个请求发送到端点。注意:client_id 和 client_secret 仅对机密客户端或任何已获得客户端凭据的客户端是必需的。

所以恶意应用在获取用户名和密码之前是无法访问任何资源的,否则无法获取访问令牌。即使它使用您的官方应用程序的身份。

由于您提到的确切原因,提供的示例实际上是一个非常糟糕的示例 - 攻击者可以提取客户端机密并冒充客户端。

此授权的安全性取决于该客户端机密的保护程度。此外,它依赖于通道的保护程度,因此攻击者无法在中间创建一个人并从请求中提取秘密。如果你能同时保护这两者,那么你就处于一个相当不错的位置,但对于移动应用程序来说,这真的很难做到。

回答你的问题:你真的不能。您可以通过以下方式缓解其中一些问题:

  • 为应用程序的每个实例使用唯一的客户端 ID 和机密,但这会使管理变得非常复杂
  • 或者您可以将机密存储在受信任的硬件存储中,但协议需要逐字记录机密
  • 或者您可以修改协议以使用基于令牌的客户端标识符,例如使用由客户端密钥签名的 JWT 或 SAML 令牌,这样传递由密钥签名的短期断言而不是密钥等。

将所有这些加在一起,您就有了一种非常可靠的方法来识别客户端,但它肯定不是万无一失的,它肯定有其缺点:可管理性是一个 PITA,你如何进行初始秘密交换?等等。