PostgreSQL上金融应用程序的身份验证方法的选择


15

首先介绍一些背景。

LedgerSMB项目是在PostgreSQL上运行的开源财务会计软件项目。我们在用户定义的函数中实现了大量的业务逻辑,这些逻辑充当程序对象方法与数据库行为之间的主要映射工具。当前,我们将数据库用户用作身份验证用户,部分是通过选择(这允许集中的安全逻辑,以便可以编写其他工具并重复使用授予用户的权限),另一部分是根据需要(在从SQL-Ledger分叉之后)在该代码库上加装安全性的选择不多)。

这使我们可以访问PostgreSQL可以访问的合理数量的单点登录选项,从LDAP到Kerberos5。我们甚至可以在涉及密码的情况下使用PAM。它还允许我们在与其他应用程序集成或允许其他客户端界面时重用权限。对于财务会计应用程序来说,这似乎是一个净赢。

涉及明显的成本。对于Web应用程序,我们非常受支持的http auth类型限制。例如DIGEST完全被淘汰。BASIC可以正常工作,并且我们可以很容易地实现KRB5(我计划对此提供支持,并在1.4版本开箱即用)。虽然很可能会在必要时对它们进行垫片化(例如,BASIC +带有用户名和特定根ca的cn的cn的客户端SSL证书),但不能直接在此上正确地管理非常强大的身份验证措施。

同时,我们受到了很多批评,大多数是来自开发人群,还有一些是来自dba的批评,他们告诉我应用程序应该是安全屏障,而不是数据库。我仍然认为,较小的安全范围通常更好,重用业务逻辑和安全逻辑在一起,并且重用业务逻辑而不在同一级别重用安全逻辑使我感到非常危险。该程序。

我在这里错过任何重大的权衡吗?是否有我没有考虑的陷阱?


1
交叉发布到pgsql-General邮件列表。请参阅从此处开始的线程。
Craig Ringer

Answers:


17

我认为您正在混淆身份验证授权

我完全同意将安全模型保留在数据库中是明智的,尤其是在设计LedgerSMB时要考虑到多个客户端的访问。除非您计划使用中间件层进行3层迁移,否则将用户用作数据库角色是非常有意义的,尤其是对于会计应用程序而言。

但这并不意味着你必须进行身份验证使用PostgreSQL的支持的验证方法对数据库用户。您的数据库用户,角色和授予只能用于您的授权

例如,这是如何用于Web ui的:

  • jane连接到Web ui服务器并使用所需的任何方法进行身份验证,例如HTTPS X.509客户端证书握手和DIGEST身份验证。现在,服务器已接受来自用户的连接,该连接确实是jane

  • 服务器使用固定的用户名/密码(或Kerberos或您喜欢的任何一种)连接到PostgreSQL,并以用户身份向db服务器进行身份验证webui。db服务器信任webui对用户的身份验证,因此webui已被赋予适当GRANT的权限(请参见下文)。

  • 在该连接上,服务器SET ROLE jane;用来承担用户的授权级别jane。在运行RESET ROLE;一个或另一个SET ROLE运行之前,该连接将以janeSELECT current_user()等将报告的相同访问权限运行jane

  • 服务器维护其所拥有的数据库连接之间的关联SET ROLE,以jane和为用户的web会话jane,不容许该通过与其他用户的其他连接,无需新的使用PostgreSQL的连接SET ROLE其间。

您现在正在服务器外部进行身份验证,但仍在服务器中维护授权。Pg需要知道存在哪些用户,但不需要密码或身份验证方法。

看到:

细节

Webui服务器控制查询的运行,并且不会让jane原始SQL运行(我希望!),因此jane不能通过RESET ROLE; SET ROLE special_admin_user;Web ui运行。为了增加安全性,我将向拒绝的服务器添加一个语句过滤器SET ROLERESET ROLE除非该连接位于或进入未分配的连接池中。

您仍然可以在其他客户端中对Pg使用直接身份验证;您可以自由地混合搭配。您只需要向用户授予可以通过Web登录GRANTwebui用户的权限SET ROLE,然后为这些用户提供所需的任何常规CONNECT权限,密码等。如果您希望将它们设置为仅用于Web,则REVOKE它们CONNECT对数据库的权限(以及从中获得的权限public)。

为了使身份验证/授权的划分变得容易,我有一个特殊的角色assume_any_userGRANT每个新创建的用户都应该扮演这个角色。然后GRANT assume_any_user,我使用了受信任的Web前端之类的东西使用的真实用户名,从而赋予他们成为自己喜欢的任何用户的权利。

使是很重要的assume_any_user一个NOINHERIT角色,所以webui用户或任何具有其自身没有privilges,只能对数据库的作用,一旦它SET ROLE的真实用户。在任何情况下都不应webui成为超级用户或数据库所有者

如果您是连接池,则可以SET LOCAL ROLE仅在事务中使用来设置角色,因此可以在COMMIT或之后将连接返回到池ROLLBACK。注意RESET ROLE仍然可以使用,因此让客户端运行他们想要的任何SQL仍然是不安全的。

SET SESSION AUTHORIZATION是此命令的相关版本,但功能更强大。它不需要角色成员身份,但这是一个仅限超级用户的命令。您不希望您的Web ui以超级用户身份连接。它可以被逆转RESET SESSION AUTHORIZATIONSET SESSION AUTHORIZATION DEFAULTSET SESSION AUTHORIZATION theusername重新获得超级用户权限,所以它不是一个特权坠安全屏障无论是。

SET SESSION AUTHORIZATION如果您是角色成员但不是超级用户,那么像但一样工作但不可逆的命令就可以了。目前还没有,但如果您小心的话,仍然可以很好地将身份验证和授权分开。

范例与说明

CREATE ROLE dbowner NOLOGIN;
CREATE TABLE test_table(x text);
INSERT INTO test_table(x) VALUES ('bork');
ALTER TABLE test_table OWNER TO dbowner;

CREATE ROLE assume_any_user NOINHERIT NOLOGIN;
CREATE ROLE webui LOGIN PASSWORD 'somepw' IN ROLE assume_any_user;

CREATE ROLE jane LOGIN PASSWORD 'somepw';
GRANT jane TO assume_any_user;
GRANT ALL ON TABLE test_table TO jane;

CREATE ROLE jim LOGIN PASSWORD 'somepw';
GRANT jim TO assume_any_user;

现在连接为webui。请注意,你不能做任何事情test_table,但你可以 SET ROLEjane然后你可以访问test_table

$ psql -h 127.0.0.1 -U webui regress
Password for user webui:

regress=> SELECT session_user, current_user;
 session_user | current_user 
--------------+--------------
 webui        | webui
(1 row)



regress=> SELECT * FROM test_table;
ERROR:  permission denied for relation test_table

regress=> SET ROLE jane;
SET

regress=> SELECT session_user, current_user;
 session_user | current_user 
--------------+--------------
 webui        | jane
(1 row)

regress=> SELECT * FROM test_table;
  x   
------
 bork
(1 row)

需要注意的是webui SET ROLEjim,即使已经SET ROLEd至jane及,即使jane没有被GRANT编承担角色的权利jimSET ROLE设置您的有效用户ID,但不会删除您SET ROLE担任其他角色的能力,这是您连接的角色的属性,而不是当前的有效角色。因此,您必须仔细控制对SET ROLEand RESET ROLE命令的访问。SET ROLE尽管确实很高兴,但AFAIK无法永久建立连接,真正成为目标用户。

比较:

$ psql -h 127.0.0.1 -U webui regress
Password for user webui:

regress=> SET ROLE jane;
SET

regress=> SET ROLE jim;
SET
regress=> SELECT session_user, current_user;
 session_user | current_user 
--------------+--------------
 webui        | jim
(1 row)

至:

$ psql -h 127.0.0.1 -U jane regress
Password for user jane:

regress=> SET ROLE webui;
ERROR:  permission denied to set role "webui"
regress=> SET ROLE jim;
ERROR:  permission denied to set role "jim"

这意味着SET ROLE与以给定角色登录并不完全相同,您必须牢记这一点。

webui不能做到SET ROLEdbowner因为还没有做到GRANT这一点:

regress=> SET ROLE dbowner;
ERROR:  permission denied to set role "dbowner"

因此,就其自身而言,它几乎是无能为力的,它只能承担其他用户的权利,并且仅当这些用户启用了Web访问时才可以。


1
顺便说一句,您可能想了解pgbouncer一些细节。
克雷格·林格

2
哦,DISCARD ALL是将权限放回默认值的另一种方法。我真的希望Pg有一个SET ROLE NORESET或类似的...
Craig Ringer 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.