赞
踩
关于技术流系列博客
开物成务,厚积薄发。技术流系列博客-以“短小精悍”的形式普及数据库硬核技术。相信大家的每一次阅读,都会距离数据库内核更近一步。每一份来自你们的关注,都是我们坚持输出的满满能量!
行级安全(RLS,Row-Level Security)可控制用户访问数据库的查看权限,简化应用程序的设计和编码,帮助实现数据库行级数据的访问控制。每一次尝试访问数据,都会受到 RLS 的限制,RLS 使得数据库安全系统更加稳定、可靠、强大。
RLS 主要的应用场景是可以确保不同的用户访问不同的数据内容。例如,针对公司员工信息,某部门组长只能访问与其部门相关的员工信息数据行,而 HR 可以访问整个公司所有员工的信息;一个地区的用户,只能访问该地区用户的数据,不能访问其他地区的用户数据,从而符合数据安全要求和通用数据保护条例(GPDR, General Data Protection Regulation)。
目前大多数数据库,例如 Oracle,SQL Server,PostgreSQL 等,都实现了行级安全控制。后续以 PostgreSQL 的行级安全为例,讲解行级安全控制的功能。
PostgreSQL 的每个用户除了可以通过 SQL 标准权限系统 GRANT 获取权限外,TABLE 还可执行行安全策略(RSP,Row Security Policies)。
行级安全可以限制每个用户的正常查询可以返回哪些行,或通过数据修改命令(INSERT、UPDATE、DELETE)修改哪些行。这个特性,就是上述文章提到的 RLS 在 PostgreSQL 中的应用实现。
默认情况下,表没有任何 RSP,因此用户根据 SQL 权限系统对TABLE 有访问权限,表中的所有行都可以进行查询和更新。
当一个 TABLE 启用了 RSP,则所有对 TABLE 数据行正常的查询或修改操作,都必须被 RSP 允许。如果 TABLE 不存在 RSP,则使用默认拒绝策略,意味着没有行可见或可以修改。
RSP 可以指定操作命令、限制角色或两者同时指定;可以指定RSP应用于所有操作命令(ALL),或 SELECT、INSERT、UPDATE 、 DELETE 其中之一;可以将多个角色分配给一个 POLICY,并且正常角色成员资格和继承规则生效。
RLS 的实现逻辑主要是通过控制以下内容:
(1)用户、角色及其成员
(2)操作对象
(3)满足条件的数据
(4)具体命令操作
RLS 的控制主要涉及以下的语法:
(1)行安全策略操作
(2)表 RLS 开关操作
具体操作步骤代码解析如下:
(1)创建 POLICY
-
- CREATE POLICY name ON table_name
- [ AS { PERMISSIVE | RESTRICTIVE } ]
- [ FOR { ALL | SELECT | INSERT | UPDATE | DELETE } ]
- [ TO { role_name | PUBLIC | CURRENT_ROLE | CURRENT_USER | SESSION_USER } [, ...] ]
- [ USING ( using_expression ) ]
- [ WITH CHECK ( check_expression ) ]
name
POLICY 名称。一个表的多个 Policies 名称唯一;表之间的 Policies 名称无关。
table_name
TABLE 的名称,可以是 schema_name.table_name 的格式。
AS 生效策略
PERMISSIVE:宽松的,多个 PERMISSIVE 策略之间是 OR 关系;RESTRICTIVE:严格的,多个 RESTRICTIVE 策略之间是 AND 关系。
Command
POLICY 适用的命令。有效选项:ALL(默认),或者SELECT、INSERT、UPDATE、DELETE 其中之一。
role_name
用户/角色名称、PUBLIC(默认)、CURRENT_ROLE、CURRENT_USER、SESSION_USER 其中之一或其组合。
using_expression
任何返回布尔类型的 SQL 条件表达式,但不可以是聚合或窗口函数。如果启用了行级安全,则此表达式将添加到引用该表的查询中。表达式返回 true 的行将是可见的;表达式返回 false 或 null 的行对用户都将不可见(在 SELECT 中),并且不可用于修改(在 UPDATE 或 DELETE 中);这些行将被默默地过滤,不会出现报错,用户无感知。
check_expression
任何返回布尔类型的 SQL 条件表达式,不可以是聚合或窗口函数。如果启用了行级安全,则此表达式将用于表的 INSERT 和 UPDATE 语句, 仅允许 INSERT 或 UPDATE 表达式计算为 true 的行。如果对 INSERT 或 UPDATE 产生记录,表达式的计算结果为 false 或 null,则将引发错误。check_expression 是针对行提交的新内容而不是原数据进行评估的。
(2)修改 POLICY
-
- ALTER POLICY name ON table_name RENAME TO
- new_name
- ALTER POLICY name ON table_name
- [
- TO { role_name | PUBLIC | CURRENT_ROLE | CURRENT_USER | SESSION_USER } [, ...]
- ]
- [
- USING ( using_expression ) ]
- [ WITH CHECK
- ( check_expression ) ]
(3)删除 POLICY
DROP POLICY [ IF EXISTS ] name ON table_name [ CASCADE | RESTRICT ]
(4)修改 TABLE
-
- ALTER TABLE [ IF EXISTS ] [ ONLY ] name [ * ]
- DISABLE ROW LEVEL SECURITY -- 启用RLS
- ENABLE ROW LEVEL SECURITY -- 禁用RLS。RSPs可以继续存在。
- FORCE ROW LEVEL SECURITY -- RLS应用于TABLE的OWNER
- NO FORCE ROW LEVEL SECURITY -- RLS不应用于TABLE的OWNER
如果一个表上有多个行安全策略,它们的生效顺序必须满足以下 2 条规则:
(1)当不同命令类型的多个策略应用于同一命令时(例如,SELECT 和 UPDATE 策略应用于一个 UPDATE 命令),那么用户必须同时拥有这两种类型的权限(例如,从 TABLE 中 SELECT 行以及允许 UPDATE 它们的权限)。因此,使用 AND 运算符将两种策略的表达式组合在一起。
(2)当同一命令类型的多个策略应用于同一命令时,必须至少有一个 PERMISSIVE 策略授予对 TABLE 的访问权限,并且所有 RESTRICTIVE 策略都必须通过。因此,所有 PERMISSIVE 策略表达式使用 OR 组合,所有 RESTRICTIVE 策略表达式使用 AND 组合,结果使用 AND 组合;如果没有 PERMISSIVE 策略,则拒绝访问。
定义 POLICY 时,Command 类型和 USING、WITH CHECK 的适用关系如下表所示。
Command 操作类型与 Policy 类型的表达式生效关系图,如下表所示。
[a]:如果需要对现有行或新行进行读取访问(例如,引用关系中列的 WHERE 或 RETURNING 子句),则还需要 SELECT/ALL 策略。
RLS 的使用注意事项:
(1)TABLE 的 owner 才能创建、修改、删除、以及 ENABLE 和 DISABLE POLICY。
(2)TABLE 的 owner 访问数据行通常不受 POLICY 约束,但 owner 可以选择使用 ALTER TABLE ... FORCE ROW LEVEL SECURITY 来接受 RSP 约束。
(3)表上无 RSP,但是启用了表的 RLS,默认拒绝策略(所有行不可读和改)。
(4)TRUNCATE 和 REFERENCES 不受 POLICY 约束。
(5)POLICY 在用户 Queries 指定的条件或函数之前生效(除了 Leakproof 函数,Leakproof 会被优化器选择在 POLICY 之前生效)。
(6)superuser 和具有 BYPASSLRS 属性的角色在访问表时总是绕过 RLS 系统。
(7)一个表可以创建多个 POLICY,Policies 之间不重名。不同表之间的 Policies 命名没有关系,可以重复。
(8)POLICY 的表达式仅考虑要访问或更新行的当前值。
以下,以 PostgreSQL 为例进行 RLS 的实例演示。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。