服务器端 API 中的权限检查
Posted
技术标签:
【中文标题】服务器端 API 中的权限检查【英文标题】:Permissions checking in server-side API 【发布时间】:2010-10-09 13:27:28 【问题描述】:我们的产品建立在客户端-服务器架构上,服务器用 Java 实现(我们使用 POJO 和 Spring 框架)。我们在服务器上有两个 API 级别:
外部 API,它使用 REST Web 服务 - 对于外部客户端和与其他服务器的集成很有用。 内部 API,它使用纯 Java 类 - 对于内部的实际代码(业务逻辑多次调用 API 调用)以及与公司内部开发并部署为我们产品的一部分。外部 REST API 也使用内部 API。我们在内部 API 中实现了权限检查(使用 Spring 安全性),因为我们希望在最低 API 级别控制访问。
但问题来了:API级别定义了一些操作,对于当前登录的用户来说是被禁止的,但应该由服务器自己顺利执行。例如,可以禁止用户删除某些实体,但服务器可能希望删除该实体,作为用户执行的某些其他操作的副作用,我们希望允许这样做。
那么,让服务器执行实际登录用户可能被禁止的操作(在某种超级用户模式下)的最佳方法是什么?
在我看来,我们有几种选择,每种都有其优点和缺点:
-
在外部级别 API (REST) 中实施权限检查 - 不好,因为插件会绕过权限检查。
在请求被授予后关闭当前线程的权限检查 - 太危险了,我们可能允许太多本应禁止的服务器操作。
明确要求内部 API 级别在特权模式下执行操作(就像 java 安全框架中的 PrivilegedAction) - 太冗长了。
由于上述方法都不理想,我想知道解决这个问题的最佳实践方法是什么?
谢谢。
【问题讨论】:
【参考方案1】:听起来您需要两个级别的内部 API,一个暴露给插件,一个不暴露。
启用它的最佳方法是使用 OSGi(或 Spring 模块)。它允许您明确声明其他模块(即 REST 模块和插件模块)可以访问哪些包和类。这些将是您的新内部 API 的公开级别,您将使用 Spring Security 进一步有选择地限制访问。内部包和类将包含执行所有低级操作(如删除实体)的方法,您将无法直接调用它们。一些公开的 API 只会通过安全检查复制内部 API,但这没关系。
最好的方法的问题是 Spring Modules 在我看来仍然有点太不成熟,甚至无法放入一个新的 webapp 项目中。我绝不会想把它硬塞进一个旧项目中。
您可能可以使用 Spring Security 和 AspectJ 实现类似的目标,但令我震惊的是,性能开销会令人望而却步。
如果您可以重新设计您的系统,一个非常酷的解决方案是让需要安全提升的任务离线,或者让它们异步。使用 Quartz 和/或 Apache Camel(或适当的 ESB),您可以使“删除我的帐户”方法创建一个离线任务,该任务可以在将来作为具有管理员权限的原子工作单元执行。这意味着您可以在与实际发生删除的完全独立的线程中对请求删除帐户的用户进行干净的安全检查。这将具有使网络线程更具响应性的优势,尽管您仍想立即执行某些操作以保持所请求的操作已完成的错觉。
【讨论】:
【参考方案2】:安全性应用于模块的边界。如果我理解您,您的系统将安全性应用于(大致)相同 API 的两个抽象级别。这听起来很复杂,因为您必须对整个两个 API 进行双重安全检查。
考虑将 REST 所需的方法从内部 API 迁移到外部 API,并删除内部 API 中的安全内容。
外部 API 将管理外部客户端的安全性(在您的应用程序的边界) 内部 API 将严格保留供内部应用程序和插件使用(您会很乐意破解它,因为没有外部客户端与它绑定)您真的需要控制插件对您的应用程序逻辑的权限吗?有充分的理由吗?毕竟,插件是由贵公司开发的。也许向插件的开发人员解释不应该做什么的正式文档,或者插件的安全测试套件验证(例如,断言插件不调用“this”方法)也可以完成这项工作。
如果您仍然需要将这些插件视为“不受信任”,请将它们所需的方法添加到您的外部 API(在您的应用边界上)并为每次使用创建特定的安全配置文件:“restProfile”、“clientProfile”和“pluginProfile ”。每个人都将对您的外部 API 方法拥有特定的权限。
【讨论】:
这是我们研究的可能性之一。除了插件问题之外,它的问题在于它意味着允许主请求意味着自动允许源自该请求的后续 API 调用。 据我了解:您描述了一个有状态的场景(在“this”第一个方法调用的上下文中,只允许“这些”后续方法调用)。问题是,您的 API 是无状态的,因此,您定义了一个无状态权限模型(自然)不适合您的有状态场景。 2 解决方案:1)“statefullise”你的无状态 API 的用户(cookie/URLsessionID):服务器上的用户状态提醒你后续的 API 调用。然后,您可以选择允许(或不允许)执行此特定的无状态 API 调用。成本:在真正使用您的 API 之前有很多复杂的决策逻辑。 2) “statefullise”你的 API(打破它)供你的无状态用户使用:你的 api 似乎是面向“技术”的。制作用例,并为每个场景构建一个特定的业务、应用程序范围和长期有状态的对象。在第一次调用 statefull 对象 API 时,用户被注册。在随后的通话中, 用户被“识别”并允许继续。成本:破坏你的整个 API,但你的“技术”API 前面会有一个“干净”的业务接口(这是 SOA 方式)。【参考方案3】:如果您使用的是 Spring,您不妨充分利用它。 Spring 提供AOP,允许您使用拦截器并执行这些跨系统检查,并在发生未经授权的操作时阻止该操作。
您可以在 Spring 的在线文档here 中阅读更多相关信息。
希望这会有所帮助...
尤瓦尔=8-)
【讨论】:
我的问题是概念性的,而不是技术性的。我们正在使用 Spring 安全性并且没有问题。以上是关于服务器端 API 中的权限检查的主要内容,如果未能解决你的问题,请参考以下文章