REST API 授权类型



我已经阅读了很多关于提供REST API访问的方法,但我仍然无法决定使用什么。

就我而言,我正在编写一个将由移动应用程序(android&iOS)的用户使用的REST API,因此我不提供或要求第三方访问,这让我认为我不必使用OAuth。但是,我考虑如何从多个设备提供对一个用户帐户的访问权限以及如何提供离线访问。

我的另一个考虑因素是我应该如何限制 API 访问,例如,如果使用 API 令牌,令牌过期和续订的最佳实践是什么?

您的问题中有几个主题:

  • OAuth2 对于互联网上公开的内部 API 有什么好处?
  • 我应该如何管理代币?
  • 用户如何通过多个设备获得访问权限?
  • 用户如何进行离线访问?

我将在下面讨论这些问题。

奥特2

OAuth2 为多种复杂程度不同的身份验证方案提供了标准化协议。最复杂的用例之一是"授权代码授予"流,它允许资源所有者(用户)通过中介(授权服务器)授予对客户端应用程序的特定访问权限。这就是您"使用谷歌登录"时发生的情况。与自制解决方案相比,使用 OAuth2 的优势在于该协议对各方都很清楚,并且不太可能包含基本缺陷。缺点可能是协议不是那么灵活,因此某些自定义方案可能很难在 OAuth2 的边界内得到支持。如果您没有立即需要任何典型的 OAuth2 场景(或要求使用 OAuth2 的利益相关者),那么我建议不要从它开始,而是自己实现一个简单的令牌方案。

管理令牌

管理 API 访问的最常见方法是使用令牌。令牌在用户登录时生成,通常使用 HTTPS 上的用户名和密码。令牌保留在服务器上,并且必须由应用在每个请求中提供。这类似于 Web 应用程序中使用的会话 ID,它由服务器上的应用程序容器在内存中自动生成和处理,并通过 cookie 或请求参数传递。API 令牌通常由应用程序本身的安全层处理,保留在数据库中,并通过"授权"标头传递。

令牌应具有到期日期。应确定此操作的最佳间隔,以及令牌续订是自动的(每次用户访问 API 时)还是显式的(强制用户在过期后重新输入凭据)。这取决于应用程序的类型和所需的安全级别。令牌也可以在服务器上手动撤销。

多个设备

每个令牌都可以与特定用户和设备相关联,以允许在多个设备上访问。这意味着每个设备都必须唯一标识,通常使用 IMEI 代码。这样可以轻松地一次撤销特定设备或用户的所有令牌。

离线访问

提供脱机访问的典型方法是在设备上缓存相关数据。例如,谷歌地图应用允许您离线使用地图的特定区域。为了避免(太)过时的数据,您可以跟踪令牌的到期日期,并在此日期之后使缓存的数据失效。需要注意的问题是用户对脱机编辑的处理。当设备再次联机时,必须处理这些编辑。当遇到对相同数据的同时编辑时,需要一种策略来解决冲突,例如:

  • 一个编辑会覆盖另一个编辑,具体取决于编辑类型或用户的角色
  • 上次编辑将被忽略或提供给最后一个编辑器进行解析
  • 某些类型的修改可能会自动"合并"
  • 等。

另一个简单而简单的策略是禁止离线时进行所有编辑。

2 件事要保护/验证

  • 客户端应用有权使用该服务
  • 用户有权访问个人数据

应用身份验证

移动应用程序是不受信任的客户端。即使您不授予任何人访问应用程序源的权限,您也必须预料到任何类型的授权机密或机制都是不安全的,并且可能来自被黑客入侵的应用程序或其他模拟应用程序行为的恶意工具。

要对应用进行身份验证,您所能做的就是拥有客户端 ID,而不是客户端密码。 例如

http://service.com/rest?client_id=android
Reply method(String client_id) {
   if (!client_id in ["andoid", "ios"])
       return Unauthorized();
}

您可以将该架构更改为更难猜测的内容,但您所做的任何事情都归结为相同的安全级别。

用户身份验证

保护用户数据至关重要,幸运的是是可能的。关键区别在于,机密不是静态硬编码到应用程序中的,只有用户知道。

对用户进行身份验证的一种"简单"方法是使用他们拥有的其他帐户。像 http://openid.net/connect/faq/这样的架构允许你做到这一点。

您基本上将身份验证委托给其他服务。 并获取(每个服务)唯一的用户 ID,您可以在代码中将其用作所有用户数据的键。攻击者无法伪造此令牌,因为您的服务器可以通过询问其他服务来验证令牌是否有效。看起来大致像

http://service.com/rest?client_id=android&user_token=aasjkbn9nah9z23&user_auth_service=facebook
Reply method(String client_id, user_token, user_auth_service) {
   if (!client_id in ["andoid", "ios"])
       return Unauthorized();
   authenticated_user_id = user_auth_service.getUserIdOrFail(user_token);
   accessDatabase(authenticated_user_id);
}

攻击者仍然可以从一些邪恶的应用程序使用您的服务,但无论如何都无法访问他无法访问的帐户。

而且,如果将访问令牌硬编码到应用程序中,则最好不要使它们过期,或者确保以某种方式在应用程序中专门处理这种情况。总有用户的应用程序版本过时。

最新更新