大多数开发人员最终都会构建和重建访问控制——被迫根据新的客户、产品或安全需求进行重构。为什么?
访问控制在几乎任何应用程序中都是必须的,但大多数开发人员最终都会一次又一次地构建和重建它——被迫随着新客户、产品或安全需求的出现而进行重构。
为什么?通常,他们会犯四个关键错误中的一个或多个, 从而阻止他们拥有可以升级的灵活访问控制层,而无需在每次有新产品需求时重新构建它。
在深入研究这些之前,我们首先需要承认权限是困难的,而且随着世界进入云原生生态系统和微服务,它们变得越来越难。让我们试着理解为什么。
是什么让权限变得复杂?
从单体应用到分布式微服务
当应用程序被构建为单体时,谁连接到应用程序中的什么的决策过程可以被整合到一个地方,通常通过使用特定的框架,例如 Spring、Django 或 Python。
在使用分布式微服务时,尤其是在多语言结构中,这些解决方案不再适用,因此您最终不得不在您正在构建的每个小微服务和组件中添加一些访问控制。这就产生了一个问题,我们难以升级、添加功能和监控代码,因为它在不同的微服务之间复制。
连接到第三方服务
这不仅仅是您提供的服务:将您的应用程序连接到第三方服务(如身份验证、计费、分析、机器学习代理或数据库)的能力已成为构建任何应用程序的关键方面——这需要我们管理我们自己云之外的元素的访问控制。
新的、复杂的权限模型
我们想要执行权限的策略、规则和模型也变得越来越复杂。应用程序通常从管理员/非管理员模型开始,然后迅速转向越来越复杂的模型,例如RBAC、ReBAC和ABAC。我们对应用程序以及我们可以在其中进行协作的不同方式的期望从未如此高,从而产生了对不断发展的复杂策略的需求。
安全与合规
如果在过去,执行 SOC 2、ISO 或满足 GDPR 或 CCPA 标准是不寻常的,那么今天,这些标准对于基本上任何 B2B(通常是 B2C)应用程序都很常见。
这些标准以及 HIPPA 和 PCI 都有许多与应用程序访问控制的制衡相关的要求。
通过实施良好的访问控制,我们可以显着减少满足合规标准所需的困难。几乎所有正在构建的解决方案都期望拥有审计等功能,并结合对访问控制级别的可见性,您可以与审计员共享安全性和合规性——也许不是在第一天,但可能很快就会出现。
如果这还不够,那么在构建访问控制的挑战中会出现很多安全摩擦和漏洞。毫无疑问,损坏的访问控制是 OWASP 漏洞源列表中的首要 A1 项目,在所有调查中发生率最高。
权限不仅是我们如何管理和构建事物的问题,而且还会在我们的生产中产生安全问题,我们可能会面临安全事件。
现在我们了解了问题的深度,让我们跳入人们经常最终实施到他们正在构建的访问控制中的常见反模式,从而产生安全漏洞。
反模式
1. 混合“身份验证”——身份验证与授权
IAM瀑布
混淆身份验证 和授权 可能是最常见的陷阱。尽管都属于 IAM 空间,但两者却截然不同。简而言之,IAM空间由三个部分组成: 身份管理(IM)、身份验证 (AuthN)和授权 (AuthZ)。
组织方面使用 OKTA 和 Azure Active Directory 等身份管理解决方案,定义不同的组织身份及其关系。
身份验证在产品端完成,您在允许身份进入产品之前验证身份(登录)。
授权 是让我们在产品中 强制执行和检查权限的层。
这三个步骤相互渗透,但我们必须了解它们的区别。
角色翻译
身份管理、身份验证和授权之间的混淆来源之一源于它们对角色的使用。Roles 的概念通过 IAM 空间存在,但每个部分的含义各不相同。
身份管理角色表示组织内的角色(如“营销主管”或“安全团队成员”)。这些角色与在应用程序级别使用的角色(如“管理员”、“读者”或“查看者”)截然不同。将 IM 组织角色转换为应用程序级授权角色并不总是一个简单的过程,但它显然是一个需要解决的问题。
此翻译的结果(例如,决定我们的营销负责人,他是营销团队的一部分,应该具有 CMS 的编辑角色)应保存为身份验证生成的 JSON Web 令牌 (JWT) 的一部分层。
JWT 还应该用来做什么?很高兴你问。
使用 JWT
基本上,将 IM 角色转换为授权层角色 (或从组织角色转换为应用程序级别角色)应该是 JWT 中唯一包含的内容。
开发人员经常倾向于过度使用 JWT,有时甚至会存储用户应该在其中访问的所有路由。这是一个坏主意,原因如下:
混合身份验证和授权层会弄乱我们的代码。
更改角色需要用户注销并重新登录,这可能会影响用户体验和整体应用程序性能。
由于使用 RESTful API、GraphQL 或任何其他基于 HTTP 的解决方案为每个请求发送 JWT,因此创建臃肿的 JWT 会显着降低应用程序的性能。
JWT 中可以存储多少数据是有限制的。如果我们继续添加更多规则,我们最终会耗尽存储空间。
避免这种情况的最佳方法是让 JWT 仅包含用户身份的声明和范围以及他们在组织内的关系,并将所有其他与授权相关的信息保存在应用程序内的单独层中。
说到为授权创建一个单独的层,开发人员犯的下一个常见错误是将应用程序逻辑与授权逻辑混为一谈。
2.混淆应用逻辑和授权
在构建应用程序时,我们有应用程序应该做什么的逻辑,并且我们有允许谁在其中执行哪些操作的逻辑。
这两个逻辑集的组合很容易导致我们的意大利面条代码由不相关的元素混合而成。如果我们需要升级应用程序或授权层(这很可能在某个时候发生),我们最终将不得不挑选不同的代码元素,试图找出哪些与应用程序相关,哪些与应用程序相关。授权相关。
当这两个逻辑集结合在一起时,它们不可避免地会有机地增长并变得越来越繁琐,使未来任何分离、编辑、更新或升级它们的工作都变成一场噩梦。
这里还有一个性能问题。假设我们的应用程序检查用户的付款状态以批准或拒绝访问某些功能。作为应用程序流程的一部分,每次都检查这一点可能会严重影响应用程序的性能。
解决此问题的更好方法是将我们的策略与我们的代码分离。这样,授权层就可以在后台运行,监控用户的支付状态。每当我们想要检查该状态时,它已经在授权层中可用,无需每次都获取它。
3. 混合访问控制层
每个应用程序都需要多层访问控制:
物理访问控制,例如在我们的门窗上锁。
网络级访问控制,如防火墙、VPN 和零信任网络。
基础设施级别的访问控制,例如限制哪些服务可以相互通信。
最后,应用级访问控制。
这些层中的每一层都有不同的需求、要求、策略和模型。理想情况下,我们将拥有一个统一的界面/后台,我们可以在其中查看、管理和审核所有这些不同的层。将它们作为代码进行管理的能力会更好,因为它允许我们在源代码控制中对它们进行管理和运行测试。
我们经常看到开发人员在这方面犯的主要错误是将他们的应用程序级访问控制 与为管理基础设施访问控制而构建的工具(如 AWS IAM)相结合。
最初,这可能看起来是个好主意——AWS IAM 是一个非常强大的工具,可以将许多东西映射到对象中,这就是工程师使用它来映射他们的应用程序级访问控制的原因。那么为什么这不是一个好主意呢?让我们看一个具体的例子。
我们经常遇到工程师使用 AWS 中的 SS3 存储桶来映射他们的应用程序级访问控制。因为他们的数据无论如何都存储在存储桶中,所以他们觉得他们不妨为应用程序本身使用存储桶的访问控制。虽然这表面上听起来不错,但很容易看出事情何时开始出错。
当您想要迁移到不同的云,甚至是同一云中的不同存储层时,您很有可能不想再使用存储桶——您会想要使用 RDS、Redshift 或 Snowflake . 仅仅因为您的应用程序的需求发生了变化,您将不得不完全重构您的访问控制,因为它已耦合到特定的云组件基础架构中。
过度依赖这些特定组件的构建方式也可能是一个主要问题。许多人依赖于您配置 API 网关的方式来为您的应用程序执行强制措施。遗憾的是,AWS 鼓励您将路由放入 JWT 中——开发人员最终采用这种做法,作为他们可以大规模投入生产的东西,但从长远来看最终会后悔。
最后,重要的是要记住不同的访问层有不同的需求。如果我们忽略了这些需求,我们可能会在以后后悔并最终不得不重构我们的大部分应用程序。
4.认为你可以一劳永逸地解决它
开发人员在考虑权限构建时倾向于犯的最后一个主要错误更多是概念性的——认为他们可以一劳永逸地解决它。
许多年轻的公司都陷入了这种误解,最终一遍又一遍地重建他们的访问控制,而不是在应用程序本身中开发关键的新功能。最糟糕的是,每次 他们这样做时,他们都认为这一次将是最后一次。实际上,如果您只遵循我们在此处描述的一些反模式,那么很有可能每次客户、合作伙伴、安全性或合规性提出新要求时,您可能不得不丢弃所有您需要的东西。已经建立并从头开始。
避免这种情况的唯一方法是做好计划。构建一个不断增长、不断发展的应用程序,您必须假设您将不得不发展您的授权层以支持更多的策略和复杂的角色。您必须假设您将从 RBAC 迁移到 ABAC 或其他更复杂的模型,并在它们之上提供接口。
这并不意味着你应该从一开始就尝试构建一个完美的、面向未来的权限管理系统——尤其是如果你在一家初创公司工作。你永远不会完成。相反,专注于设置正确的基础。 如果您提前计划并避免我们在本文中讨论的错误,您将能够以更大的灵活性升级您的权限层 - 而不必每三到六个月从头开始重建它。
大多数公司都会经历同样的步骤。他们最初为他们的数据层和授权构建了良好的模式,但随着他们的前进,这些模式逐渐停止工作,他们开始面临性能问题。避免这种情况的唯一方法是将您的授权层与应用程序的逻辑分离,并准备好随着需求的出现逐渐更新它。
让我们总结一下
无论是从单体应用转向分布式微服务、将 3rd 方服务集成到您的应用程序中的需求、使用复杂权限模型的必要性,还是安全性和合规性要求的兴起,权限都变得比以往任何时候都更加复杂。
所有这些变化都要求我们采用新的最佳实践并避免 开发人员在考虑授权时犯的常见错误:
混合身份验证和授权,尤其是在将组织角色转换为应用程序级别的角色以及正确使用 JWT 时,将应用程序逻辑与授权逻辑混合,使用为基础设施访问控制设计的工具(如 AWS IAM)进行管理应用级访问控制,并认为我们可以在第一天一劳永逸地解决我们的授权问题。
最重要的是,重要的是要了解,在不断变化的应用程序中开发良好的授权层需要提前计划并构建一个灵活的解决方案,该解决方案可以升级,而无需在每次出现新产品需求时重新构建它。