停止使用 OAuth 2.0作用域进行微服务授权

授权不是身份验证,OAuth2作用域从未打算成为真正的以微服务为中心的授权体系结构的替代品

每天‬分享‬最新‬软件‬开发‬,Devops,敏捷‬,测试‬以及‬项目‬管理‬最新‬,最热门‬的‬文章‬,每天‬花‬3分钟‬学习‬何乐而不为‬,希望‬大家‬点赞‬,加‬关注‬,你的‬支持‬是我‬最大‬的‬动力‬。



我和无数的开发人员讨论过他们是如何随着时间的推移构建和发展授权系统的。一个常见的遗憾是,在 JWT 中使用 OAuth2作用域作为作出授权决策的唯一基础,这种做法会造成损失。

但是授权不是身份验证,OAuth2作用域从来就不是授权机制。在实践中,将它们用作真正的以微服务为中心的授权体系结构的替代品是一个非常糟糕的主意。那么,这种反模式是如何出现的呢?

从身份验证开始

当开发人员构建新应用程序时,他们首先需要实现的是登录系统。多亏了 OAuth2和 OpenID Connect (OIDC)等标准以及 Auth0等服务,它们可以将身份验证过程委托给外部身份提供商(如 Google、 Facebook 或 GitHub)。然后是授权: 确定用户实际可以做什么。

OAuth2作用域的诱惑

开发人员实现的第一个授权模式涉及到区分“普通用户”和“管理员”创建 OAuth2作用域来表示“ admin”权限非常容易。当确定用户是登录的管理员时,开发人员依赖身份验证系统将此管理作用域放入为该用户创建的 JSON Web Token (JWT)中。每次对受保护资源的调用都会检查 JWT 是否存在这个“管理”范围,而且生活似乎很美好。除了生活很少那么简单,任何严肃的应用程序很快就会遇到四个问题。

1. 范围爆炸

应用程序可以拥有多种类型的资源,每种资源(文档、报告、项目、存储库)都支持几种不同的操作(创建、读取、更新、删除、列表)。细粒度的权限系统通常会创建这些资源/操作元组的笛卡儿积,从而产生数十(或数百)个作用域。将所有这些作用域注入 JWT 是不可能的,因为 HTTP 授权头最终将超过大小限制。

2. 陈旧的许可证

由于 JWT 是在登录时生成的,其生命周期通常为1-24小时,因此依赖于 JWT 中编码的作用域而不是实时权限检查的应用程序将面临基于过时的用户安全属性快照作出授权决策的非常严重的风险。将授权绑定到令牌的生命周期并不完全是“设计上的安全”: 当管理员更改用户的属性或角色时,他们希望这些更改近乎实时地影响该用户的权限。在新权限生效之前必须等待令牌过期是一种安全反模式,并且在已知违规的情况下是危险的。为 JWT 创建一个撤销系统是困难的,并且超出了创建它们的大多数系统的范围。

3. 没有资源上下文

OAuth2作用域可以指定一般权限,如 read: document,但是应用程序通常必须在特定资源的上下文中作出授权决定。例如,Alice 拥有“公司战略”文档的 read: document 权限,但是没有“ Bob 的绩效评估”文档的 read: document 权限。任何真实场景(例如,在特定资源上实现访问控制列表)都需要一个真实的授权系统。

4. 性能问题

避免长寿命 JWT 的安全隐患的唯一实用解决方案是依赖于非常短的令牌生命周期。首先使用 JWT 进行授权的原因是它们不需要向服务器返回检查。如果 JWT 必须每分钟更新一次,那么它们是两个世界中最糟糕的: 它们总是代表一种陈旧的状态(即使只有一分钟) ,而且不断地需要重新发布它们会给登录系统带来更高的操作负载,从而导致性能问题,因为使用 OAuth2协议的身份验证是昂贵的。出于授权目的使用身份验证系统毫无意义,因为授权调用在用户会话期间发生的次数是身份验证的100倍。

构建授权的正确途径

授权应该始终实时完成,就在代码想要访问敏感资源之前。授权组件或服务应该使用用户的当前属性以及特定的资源上下文作为决策引擎的输入,以便在决策引擎评估要执行的操作的授权策略时使用。该决策引擎应该部署在与应用程序相同的子网中(理想情况下应该作为同一 pod 中的边车容器) ,以便它能够以100% 的可用性和毫秒级的延迟进行操作。

其他人同意..

当然,我们不是第一个做出这种观察的人。正如 Auth0的首席架构师 Vittorio Bertocci 在他的博客文章中雄辩地描述的那样,OAuth2作用域从来没有打算成为一种授权机制: 它们的发明是为了让身份提供者允许用户将他们的权限和数据的一个子集委托给应用程序。

我同意 Vittorio。使用 OAuth2作用域替代实际的授权系统被认为是有害的。一种更好的方法是将授权看作是一种独特的操作,它位于身份验证的下游,对于正确设计和实现同样至关重要。

发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章