是什么阻止另一个应用窃取我的 Google OAuth 客户端 ID?

What prevents another app from stealing my Google OAuth client ID?

我创建了一个 Android 应用程序,它使用 AppAuth 通过 Google OAuth 进行身份验证。在 Google 云平台控制台中,我为我的应用程序创建了一个 Android OAuth 2.0 客户端 ID,并提供了应用程序包名称和签名证书指纹。一切正常。

我想验证只有我的应用程序可以使用该客户端 ID。所以我用不同的包名创建了第二个应用程序,并用不同的签名证书对其进行了签名。使用相同的客户端 ID,我仍然能够使用 Google 进行身份验证并访问 API。我认为情况不应该如此。我正在查看 AppAuth 的源代码,看起来它在身份验证流程中从未使用过应用程序签名或包名称。它当然使用 PKCE,但我预计会发生更多事情。

因此,如果我可以轻而易举地窃取我自己的客户端 ID,那么如何阻止其他人从我的 APK 中提取我的客户端 ID 并将其用于身份验证?根据我的包名称很容易找出我用于重定向 URI 的自定义方案。因此,rouge 应用程序可以将 AppAuth 配置为使用类似的重定向 URI 并捕获授权结果。由于 PKCE 仅用于验证授权请求和代码交换是否来自同一个地方,一个 rouge 应用程序会同时执行这两项操作,因此那里也没有真正的保护。

我可以将客户端 ID 类型切换为 Web 或其他,但这需要我使用客户端密码,如果将其嵌入到应用程序中同样不安全。

我是不是遗漏了什么或者 Google OAuth 是否完全按照预期工作?

对于客户端 Google OAuth 2,您的客户端 ID 并不重要。客户端执行 OAuth 流程,客户端接收 OAuth 令牌。神奇的是客户端必须授权Google。任何人都可以窃取您的客户 ID,但他们不能用它做任何事情。作为 OAuth 生命周期的一部分,您应该验证 OAuth 令牌。您的后端不应该盲目地接受来自客户的任何东西 - 或者任何不受您绝对控制的地方。

您的客户 ID 不是秘密,您可以在代码中明确说明。

必须保密的是Client Secret。Client Secret不参与客户端认证。客户端密码用于您的后端服务器。

我认为您混淆了流程。当客户端应用程序(您的应用程序、网络浏览器等)使用 Google 帐户进行身份验证时,您的应用程序未获得授权。客户端正在被授权。客户应该对他们访问的网站(或应用程序)做出良好的判断,并使用他们的 Google 登录名。客户可以用他们的令牌做的唯一一件事就是访问他们自己的数据(Google Drive、Gmail 等)。如果您的后端服务器接受客户端的 OAuth 令牌来管理访问,那么您有责任验证该令牌及其在您系统上的预期用途以及该令牌的授权方。

更好的选择是在后端(例如您的网络服务器)执行身份验证和授权。然后您可以实施 Google OAuth 重定向以将 OAuth 令牌发送到您的服务器。您受到保护,因为只有授权的来源(例如您的域名)和授权的重定向 URI(您的 Web 服务器上的端点)可以参与身份验证过程。然后将令牌存储在客户端会话中,必要时更新,根据需要添加授权范围等。

我经常使用这两种方法(客户端、服务器端)并且都很好用。

我想在这里添加一个后记,与 Financial Grade APIs 中移动应用程序的建议相关,以使用声明的 HTTPS 方案来接收登录响应。这会将客户端 ID 的使用限制在具有您的数字签名的应用程序中。

有关详细信息,请参阅我的博客文章,其中描述了任何人都可以使用的代码示例 运行:

只有本机和单页应用程序没有客户端密码,因此他们必须切换到其他内容。这里必要的保护是重定向URL。对于网络托管的单页应用程序,无论如何设置,这都不是问题。它们正是在此重定向 URL 上托管的。对于本机应用程序,必须完成另一个步骤。 Android 和 iOS 允许使用“App-Claimed https URL 重定向”。这会将 https URL 直接绑定到应用程序。可以请求这些声称的 URL 重定向,然后必须通过特定地址上的签名进行确认:https://developer.android.com/training/app-links/verify-site-associations.

使用此方法,为了使用外国 client_id,https 重定向必须被假客户端拦截(仅限 root 环境,大多数手机不会)。 通过大量的努力,欺诈者可以 运行 另一个具有相同 client_id 的前端。 在这样的用例中:

  • 使用 API 会产生成本(例如拥有 API)
  • 前端投放广告产生收入

这是重新思考架构的一个原因。

在您描述的用例中,这不是问题,因为您不拥有 API 资源。资源所有者,即已登录 GCP 的用户,必须为其 GCP 使用付费。在 public 客户端上,您不能让客户端本身通过授权服务器进行身份验证(仅对用户进行身份验证)。