Chris van Eijk:谁绕过了 PostgreSQL 的行级安全?实测

Chris van Eijk:谁绕过了 PostgreSQL 的行级安全?实测

💡 原文英文,约2000词,阅读约需7分钟。
📝

内容提要

本文实测 PostgreSQL 17 行级安全(RLS)的绕过机制:超级用户和 BYPASSRLS 角色始终绕过;表所有者及继承其权限的成员默认绕过,FORCE 仅约束所有者本人,且所有者可自行关闭。BYPASSRLS 不随成员继承,需 SET ROLE。SECURITY DEFINER 函数随所有者绕过。TRUNCATE、目录行数统计和外键约束不受 RLS 检查。建议应用角色不继承迁移角色,并谨慎授予 TRUNCATE。

🔎

延伸解读

角色继承与绕过:关键区别

文章实测表明,表所有者的成员默认继承绕过权限,而BYPASSRLS角色的成员不会自动继承,除非执行SET ROLE。这意味着应用登录角色若属于迁移角色,且迁移角色拥有表,则应用会绕过RLS。因此,建议应用角色不要继承迁移角色,并检查pg_roles中的rolsuper和rolbypassrls属性,同时注意成员关系无法直接从pg_roles读取。

FORCE RLS的局限:仅防误用

FORCE ROW LEVEL SECURITY仅约束表所有者本人,所有者仍可自行关闭FORCE。实测中,所有者关闭FORCE后即可看到全部30行。因此,FORCE能防止应用意外以所有者身份连接导致的全面绕过,但无法阻止有意绕过。不应将所有者角色授予运行不可信SQL的应用。

RLS未覆盖的操作与侧信道

TRUNCATE、目录行数统计和外键约束不受RLS检查。拥有TRUNCATE权限的角色即使受策略约束,也能清空全表数据。应用角色虽看不到行,但可从pg_class的reltuples和pg_stat_user_tables的n_live_tup读取总行数,从而推断数据量。外键和唯一约束也会泄露行是否存在。建议谨慎授予TRUNCATE,并意识到这些侧信道风险。

SECURITY DEFINER函数与权限授予

SECURITY DEFINER函数以所有者身份运行,若所有者具有BYPASSRLS或为表所有者,则函数会绕过RLS。实测中,由BYPASSRLS角色拥有的SECURITY DEFINER函数返回全部30行。此外,只有超级用户或同时具有CREATEROLE和BYPASSRLS的角色才能授予BYPASSRLS属性。拥有ADMIN OPTION的角色可通过SET ROLE获得绕过能力。因此,应审查SECURITY DEFINER函数的所有者,并限制ADMIN OPTION的授予。

❓

Q&A

PostgreSQL 中哪些角色会绕过行级安全(RLS)?

超级用户和具有 BYPASSRLS 属性的角色始终绕过 RLS;表所有者及其继承成员默认绕过,除非表启用了 FORCE ROW LEVEL SECURITY。

BYPASSRLS 属性会通过角色成员关系继承吗?

不会。BYPASSRLS 属性不会通过成员关系继承,成员需要执行 SET ROLE 切换到该角色才能获得绕过能力。

FORCE ROW LEVEL SECURITY 能阻止表所有者绕过 RLS 吗?

FORCE 仅阻止表所有者本人绕过,但所有者可以自行执行 ALTER TABLE ... NO FORCE ROW LEVEL SECURITY 关闭它,因此 FORCE 只是防止意外,并非安全边界。

SECURITY DEFINER 函数会绕过行级安全吗?

会。SECURITY DEFINER 函数以所有者身份运行,如果所有者具有绕过权限(如 BYPASSRLS 或表所有者),则函数会绕过 RLS。

哪些操作不受行级安全检查?

TRUNCATE 操作、目录中的行数统计(如 pg_class.reltuples)以及外键和唯一约束不受 RLS 检查。

如何查询当前角色是否具有绕过 RLS 的权限?

可以查询 pg_roles 检查当前角色及其成员角色是否具有 rolsuper 或 rolbypassrls;同时查询 pg_class 检查当前角色是否为未启用 FORCE 的表的所有者。

🏷️

标签

➡️

继续阅读