[仁润云技术团队]权限系统的设计

355 阅读7分钟

本文讨论了如何使用角色的概念来管理安全策略,以及基于角色的安全应用程序安全机制在很大程度上是不够的。我讨论了我认为是保护应用程序更好的方法。

什么是角色?

当谈到应用程序安全性时,大多数人都对现有的角色概念感到满意。角色是通常代表一组行为或责任的命名实体。这些行为转化为你可以或不可以用软件应用程序做的事情。 角色通常分配给用户帐户,因此通过关联,用户可以“完成”归因于各种角色的事情。

例如,如果用户登录到应用程序,并且他们的帐户被分配了“项目经理”角色,那么我们就开始臆测该用户可以“做”项目经理在应用程序中能够做的所有事情——在项目中添加或删除员工,生成项目报告等。

在这个意义上,角色主要是一个行为概念:角色给你一个用户可以在应用程序中做什么的概念。

RBAC

一个角色主要是一个行为概念,开发软件的逻辑步骤是使用角色作为控制访问应用程序功能或数据的手段。 正如您所预料的那样,大多数人称之为基于角色的访问控制(简称“RBAC”)。 但是,实际实现和执行访问控制主要有两种方式:一种是隐式的,另一种是显式的。 目前绝大多数的软件应用程序都使用隐式访问控制。 我认为显式访问控制对于保护当今的软件应用程序来说更好。

Implicit Access Control 如前所述,角色代表行为或责任。但是,我们如何确切地知道什么样的行为或责任与角色相关?

答案是,对于绝大多数的应用程序,你不知道这个角色代表什么。您当然有一个好主意 - 您知道具有“管理员”角色的人可能会锁定用户帐户或配置应用程序的某些部分,也可能是分配了“客户”角色的用户帐户可以将商品放入购物车或请求新产品。但通常没有什么具体定义这些行为是什么。

以字符串“Project Manager”为例。 这只是一个字符串名称——除此之外,软件程序可以查看“基于这个名称,我知道用户分配这个角色可以做X,Y和Z”。 开发人员通常使用这个名字来编写应用程序。 例如,要查看用户是否被允许查看项目报告,通常会看到如下所示的代码:

 //Listing 1. Example Implicit Role-Based Access Control security check:
 if (user.hasRole("Project Manager") ) {
     //show the project report button
 } else {
     //don't show the button
 }

在此示例代码块中,软件开发人员根据“项目经理”角色(可能是项目要求)做出是否显示按钮的决定。但是请注意,上面的代码中没有任何明确的说“项目经理角色被允许查看项目报告”。没有人在软件中的任何地方定义行为陈述——这意味着“项目经理”用户可以查看项目报告,因此开发人员编写反映该假设的if/else语句。

脆弱的安全政策

像上面的例子那样的安全访问控制非常脆弱。也就是说,即使安全要求发生轻微变化,也很可能会破坏,失败或导致效率低下。 举例来说,让我们假设编写软件的团队被告知:“顺便说一下,我们需要一个新的 部门经理 角色,他们也需要能够查看项目报告。实现它”。 现在软件开发人员需要回到代码中来改变它是这样的:

 //Listing 2. Example Modified Implicit Role-Based Access Control security check:
 if (user.hasRole("Project Manager") || user.hasRole("Department Manager") ) {
     //show the project report button
 } else {
     //don't show the button
}

然后,开发人员需要更新测试用例,重新构建软件,检查存在的任何质量保证流程,以及安排重新部署到生产环境——所有这些都是由于新的安全要求。 但是,如果管理层回来并要求另一个角色能够查看报告,会发生什么?或者如果他们以后需要移除那个能力呢? 或者,如果软件需要支持在运行时动态创建或删除角色的功能,那么他们希望客户能够自己配置角色呢? 在任何这些情况下,常见的隐式(静态字符串)基于角色的访问控制方法都无法满足安全需求。作为一个理想的安全策略,在发生变化时是无需做出源码级别的调整的。

一种更好的方式

正如我们上面看到的,用隐式访问控制方法改变安全策略可能会对软件开发产生影响。如果安全策略更改没有强制代码重构,那将会好很多。理想情况下,如果安全策略可以在应用程序运行时进行更改,那么最好不要影响最终用户。这对于安全来说甚至更好,因为如果您发现错误或危险(或者您犯了策略错误),则可以将策略快速更改为正确的配置,并且软件仍然可以正常运行。

从根本上说,这些检查试图保护资源(项目报告)以及用户可以对这些资源做什么操作(例如查看/阅读这些资源)。当你把它分解到这个最原始的层次时,你就可以开始用更细粒度(和变化弹性)的方式来描述安全策略了。

 //Listing 3. Example Explicit Access Control security check:
 if (user.isPermitted("projectReport:view:12345")) {
     //show the project report button
 } else {
     //don't show the button
 }

这个例子更明确的是什么访问被控制。冒号分隔的语法在这里并不重要——这仅仅是一个例子。更重要的是,我们基本上是检查“如果当前用户可以查看ID为”12345“的”projectReport“,则显示”项目报告按钮“。也就是说,我们用一个用户帐户明确地归纳了关于特定资源实例的具体行为陈述。

什么是好的方式?

  • 减少代码重构:通过基于应用程序能做什么的代码,我们将安全性基于应用程序本身核心的东西,以及应用程序与之交互的资源变化要少得多。使用这种方法,软件开发人员可以修改安全检查,因为他们在应用程序的功能上工作 - 而不是像隐式RBAC经常需要的那样。

  • 资源和行动是直观的:代表什么被保护,以及如何采取行动是一个更自然的思考问题的方式。面向对象的编程范例和REST通信模型从根本上反映了这个观点,并因此而非常成功。

  • 灵活的安全模型:上面的代码示例并不指定如何允许用户,组或角色对资源执行操作。这意味着可以支持任何安全模型设计。例如,也许行为(权限)可以直接分配给用户。或者也许他们可以被分配给一个角色,而角色又被分配给一个用户。也许有团体的概念,与角色等有联系。可能性是开放的,可以根据您的应用程序进行定制。

  • 外部化安全策略管理:由于源代码只反映资源和行为,而不反映用户,组和角色的组合,所以这种关联管理可以外部化到代码的不同部分或专用工具或管理控制台。这意味着开发人员不需要花时间进行安全策略更改,相反,业务分析师甚至最终用户可以根据需要更改安全策略。

欢迎关注:www.renrunyun.com