首先是一些背景。
LedgerSMB 项目是一个在 PostgreSQL 上运行的开源财务会计软件项目。我们在用户定义的函数中实现了大量的业务逻辑,作为程序对象方法和数据库行为之间的主要映射工具。目前我们使用数据库用户作为身份验证用户,部分是出于选择(这允许集中的安全逻辑,以便可以编写其他工具并重用授予用户的权限),部分是出于必要(在我们从 SQL-Ledger 分叉后,有在该代码库上改进安全性的选择并不多)。
这使我们能够访问 PostgreSQL 可以访问的合理数量的单点登录选项,从 LDAP 到 Kerberos 5。我们甚至可以在涉及密码的地方使用 PAM。它还允许我们在与其他应用程序集成或允许其他客户端接口时重用权限。对于财务会计应用程序来说,这似乎是一场净赢。
有明显的成本。对于 Web 应用程序,我们非常受限于可以支持的 http auth 类型。例如,DIGEST 完全出局了。BASIC 工作,我们可以很容易地实现 KRB5(我计划支持它并为 1.4 开箱即用)。非常强大的身份验证措施无法直接对此进行适当管理,尽管我们可能会在必要时将它们填充进去(例如 BASIC + 客户端 SSL 证书,其 cn 与用户名和特定的根 ca 匹配)。
与此同时,我们遇到了相当多的批评,主要来自开发人群,偶尔来自 dba,他们告诉我应用程序应该是安全屏障,而不是数据库。我的观点仍然是较小的安全边界通常更好,业务逻辑和安全逻辑的重用是一起使用的,并且我觉得重用业务逻辑而不在同一级别重用安全逻辑是危险的的程序。
我在这里错过了任何主要的权衡吗?有没有我没有考虑的问题?
我认为您将身份验证和授权混为一谈。
我完全同意将安全模型保存在数据库中是明智的,尤其是 LedgerSMB 的设计考虑到了来自多个客户端的访问。除非您计划使用中间件层进行 3 层,否则将用户作为数据库角色是非常有意义的,尤其是对于会计应用程序之类的东西。
这并不意味着您必须使用 PostgreSQL 支持的身份验证方法针对数据库对用户进行身份验证。您的数据库用户、角色和授权只能在您喜欢的情况下用于授权。
以下是它在 web ui 中的工作方式,例如:
jane
连接到 web ui 服务器并使用所需的任何方法进行身份验证,例如 HTTPS X.509 客户端证书握手和 DIGEST 身份验证。服务器现在有一个来自它接受的用户的连接是真的jane
。服务器使用固定的用户名/密码(或 Kerberos 或任何您喜欢的)连接到 PostgreSQL,以 user 身份向 db 服务器验证其自身
webui
。db 服务器信任webui
对其用户进行身份验证,因此webui
已给予适当GRANT
的 s(见下文)。在那个连接上,服务器
SET ROLE jane;
用来假设用户的授权级别jane
。直到RESET ROLE;
或另一个SET ROLE
运行,连接以jane
与SELECT current_user()
etc 将报告的相同访问权限运行jane
。服务器维护它必须连接的数据库连接和 user 的 web 会话之间的关联
SET ROLE
,jane
不允许jane
PostgreSQL 连接被其他用户的其他连接使用,而没有新的SET ROLE
中间连接。您现在在服务器外部进行身份验证,但在服务器中保持授权。Pg 需要知道存在哪些用户,但不需要他们的密码或身份验证方法。
看:
SET SESSION AUTHORIZATION
SET ROLE
GRANT
细节
webui 服务器控制查询运行,它不会让
jane
运行原始 SQL(我希望!)所以jane
不能通过RESET ROLE; SET ROLE special_admin_user;
web ui。为了增加安全性,我会向拒绝的服务器添加一个语句过滤器,SET ROLE
除非RESET ROLE
连接在或进入未分配连接池。您仍然可以在其他客户端中自由地使用对 Pg 的直接身份验证;你可以自由混合搭配。您只需向用户授予可以通过网络登录
GRANT
的webui
用户的权限SET ROLE
,然后为这些用户提供CONNECT
您想要的任何正常权限、密码等。如果您想让它们仅用于 Web,则REVOKE
它们CONNECT
对数据库(和来自public
)的权限。为了使这样的身份验证/授权拆分变得容易,我有一个特殊的角色
assume_any_user
,我GRANT
每个新创建的用户都有。然后,我GRANT assume_any_user
使用受信任的 Web 前端之类的东西使用的真实用户名,赋予他们成为他们喜欢的任何用户的权利。创建
assume_any_user
一个NOINHERIT
角色很重要,因此webui
用户或其他任何人都没有自己的特权,并且只能在数据库SET ROLE
对真实用户起作用时才可以对其进行操作。在任何情况下都不应webui
是超级用户或数据库所有者。如果您是连接池,则
SET LOCAL ROLE
只能在事务中使用来设置角色,因此您可以在COMMIT
或之后将连接返回到池中ROLLBACK
。请注意这RESET ROLE
仍然有效,因此让客户端运行他们想要的任何 SQL 仍然是不安全的。SET SESSION AUTHORIZATION
是此命令的相关但更强大的版本。它不需要角色成员身份,但它是一个仅限超级用户的命令。您不希望您的 web ui 以超级用户身份连接。它可以用RESET SESSION AUTHORIZATION
,SET SESSION AUTHORIZATION DEFAULT
或SET SESSION AUTHORIZATION theusername
重新获得超级用户权限来逆转,因此它也不是一个放弃特权的安全屏障。如果您是角色成员但不是超级用户,那么一个可以工作但不可逆并且可以工作的命令
SET SESSION AUTHORIZATION
会很棒。目前还没有,但如果你小心的话,你仍然可以很好地分离身份验证和授权。例子和解释
现在连接为
webui
. 请注意,您不能做任何事情,但test_table
您可以SET ROLE
,jane
然后您可以访问:test_table
webui
请 注意,即使已经d 到并且即使还没有被ed 授予担任该角色的权利,也可以SET ROLE
这样做。设置您的有效用户 ID,但它不会删除您使用其他角色的能力,这是您连接的角色的属性,而不是您当前的有效角色。因此,您必须小心控制对and命令的访问。AFAIK,没有办法永久建立连接,真正成为目标用户,尽管拥有它肯定会很好。jim
SET ROLE
jane
jane
GRANT
jim
SET ROLE
SET ROLE
SET ROLE
RESET ROLE
SET ROLE
相比:
至:
这意味着这
SET ROLE
与以给定角色登录并不完全相同,您必须牢记这一点。webui
不能SET ROLE
,dbowner
因为它没有被GRANT
正确编辑:因此,它本身非常无能为力,它只能承担其他用户的权利,并且只有当这些用户启用了 Web 访问权限时。