如何使用服务器管理移动应用程序中的 OAuth 流程

Jai*_*ime 5 security oauth oauth-2.0 spring-security-oauth2 flutter

我正在开发一个带有 flutter(移动客户端)的体育移动应用程序,用于跟踪用户活动数据。跟踪活动(游泳、跑步、步行...)后,它会调用我开发的 REST API(使用 springboot),并通过 POST 传递该活动数据。然后,我的用户将能够通过 GET 调用 REST API 查看其跟踪活动的日志。

由于我知道我自己的跟踪开发不如Strava、Garmin、华为等,所以我想让我的应用程序用户连接他们的Strava、Garmin等帐户以获取他们的活动数据,所以我需要用户授权我的应用程序使用 OAuth 获取该数据。

在第一种方法中,我成功地使用授权代码授予通过 flutter 开发了 OAuth 的所有流程。授权服务器登录由 flutter 在用户代理(chrome 选项卡)中启动,一旦资源所有者完成登录并授权我的 flutter 应用程序,我的 flutter 应用程序就会获取授权代码并调用授权服务器来获取令牌。所以我可以说,我的客户端就是我的 flutter 应用程序。当 oauth 流程完成后,我将令牌发送到 Rest API,以便将它们存储在数据库中。

我的第一个想法是将这些令牌发送到我的后端应用程序,以便将它们存储在数据库中,并开发一个流程,该流程获取这些令牌、咨询资源服务器、将每个资源服务器 json 响应活动解析为我的其余 API 活动模型活动并存储在我的数据库。然后,如果资源所有者调用我的 Rest API 查询其活动,他将获得所有活动的响应(移动应用程序跟踪的活动 + Strava、Garmin、资源服务器等存储在我的数据库中的活动)。

当用户按下同步按钮并直接在客户端中映射这些响应时,我放弃了直接从客户端调用资源服务器和其余 api 的选项,因为我需要后端中这些资源服务器响应的数据为了实现奖牌功能。此外,Strava、Garmin 等都有使用限制,我不想让我的资源所有者能够在他们想要的时间按下按钮。

这是我的第一个想法的流程:

脚步:

  1. 客户端调用授权服务器启动用户代理以进行 oauth 登录。为了让资源拥有者登录并授权。url 和参数是硬编码的,在我的客户端中是硬编码的。

  2. 资源所有者登录并授权客户端。

  3. 回调是通过代码发送的。

  4. 客户端捕获回调代码并向授权服务器发送消息以获取令牌。由于某些授权服务器接受 PKCE,因此我尽可能使用 PKCE,以避免攻击并在客户端中硬编码我的客户端密钥。其他人(例如 Strava)不允许 PKCE,因此我必须在客户端中对客户端密钥进行硬编码才能获取令牌。

  5. 将令牌返回给我的客户端后,我将它们发送到我的其余 api 并存储在标识令牌资源所有者的数据库中。

调用资源服务器:

  1. 一个定期进程获取每个资源所有者的令牌,并使用从每个资源服务器返回的活动更新我的数据库。

  2. 资源所有者调用rest api并获取所有活动。

第一个想法的问题在于,一些授权服务器允许实施 PKCE (Fitbit),而其他授权服务器则使用客户端密钥来创建令牌 (Strava)。由于我需要客户端密钥来获取其中一些授权服务器的令牌,因此我已在客户端中对密钥进行了硬编码,但这并不安全。

我知道将客户端机密插入客户端是危险的,因为黑客可以反编译我的客户端并获取客户端机密。如果授权服务器中不允许 PKCE,我无法弄清楚如何在不硬编码客户端密钥的情况下获取 Strava 的资源所有者令牌。

由于我不想在客户端中对客户端机密进行硬编码,因为它不安全并且我想将令牌存储在我的数据库中,因此我认为第一种方法不是一个好的选择。此外,我正在向 REST API 创建一个 POST 请求,以便将访问令牌和刷新令牌存储在我的数据库中,如果我没记错的话,该过程可以直接从后端完成。

我的情况是,我开发了一个公共客户端(移动应用程序),它对客户端密钥进行了硬编码,因为我不知道当授权服务器不允许 PKCE 获取令牌时如何避免这样做。

因此,在思考所有这些问题之后,我的第二个想法是利用我的 REST API 并从那里调用授权服务器。因此,我的客户将是保密的,我将使用服务器端应用程序执行 OAuth 流程。

我的想法是基于这张图片。

在此输入图像描述

为了避免我的移动客户端中的客户端秘密硬编码,以下基于图像的代码流是否可以工作并安全地连接到 Strava、Garmin、Polar...?

Strava 连接示例:

移动客户端

  • 移动公共客户端调用我的 Rest API 以获取 Strava 授权服务器登录的 URI,并包含所需参数,例如:callback、redirect_uri、client_it 等。

  • 移动客户端捕获 Rest API GET 响应 URI。

  • 移动客户端启动用户代理(Chrome 自定义选项卡)并监听回调。

用户代理

  • Strava 的登录提示会显示给资源所有者。

  • 资源所有者插入凭据并推送授权。

  • 回调已启动

移动客户端

  • 当我的客户端检测到回调时,返回客户端并从回调 uri 中提取代码。

  • 通过帖子将该代码发送到我的 REST API。(https://myrestapi,代码在正文中)

REST API 客户端

  • 现在,客户端是我的 REST API,因为它将使用移动客户端获取的代码调用授权服务器。客户端将获取该代码,并在其中硬编码客户端密钥,然后调用授权服务器。通过这种方法,客户端秘密不再存在于移动客户端中,因此它是保密的。

  • 授权服务器返回令牌,我将它们存储在数据库中。

过程

  • 从我的数据库中获取这些令牌并调用 Strava 的资源服务器来获取活动。然后将这些活动解析到我的模型中并将它们存储到数据库中。

第二种方法是处理客户端机密以避免公开的好方法吗?或者我做错了什么?我可以遵循什么流程以正确的方式做到这一点?我真的被这个案例困扰了,而且由于我是 OAuth 世界的新手,我对我读过的所有信息感到不知所措。

Mic*_*ski 3

您提出的第二种方法是实现 OAuth 流程的有效方法。您的后端可以充当您需要的机密客户端,并且您可以安全地从授权服务器获取令牌。这种模式有时被称为“Backand-For-Frontend”(尽管这个名称现在有点重载)。在 Curity,我们描述了类似的东西,我们称之为令牌处理程序模式。前提是相似的,但我们的主要目标是可以利用 cookie 来管理会话的单页应用程序。

当然,您需要的是在后端和移动应用程序之间创建安全会话。在浏览器应用程序中,您只需使用带有 cookie 的普通旧会话。您必须确保在调用您的后端时没有人可以冒充您的应用程序的用户。

您可以探索的另一件事是 Stravia 是否支持动态客户端注册标准。使用 DCR,您可以将移动应用程序的每个实例注册为单独的客户端。然后,每个客户端都会收到自己的客户端 ID 和密码。这样您就不必担心秘密被窃取。

您还可以联系 Stravia,询问他们为什么不通过 PKCE 支持公共客户以及他们是否计划这样做。PKCE 是一个重要的安全 OAuth 标准,公司应寻求支持它。