DBMS_RLS包可以使虚拟私有数据库VPD(Virtual Private Database)执行于特定的PolarDB数据库对象上。
函数/存储过程 | 类型 | 返回类型 | 说明 |
---|---|---|---|
ADD POLICY(object schema, object name, policy name, function schema, policy function [, statement types [, update check [, enable [, static policy [, policy type [, long predicate [, sec relevant cols [, sec relevant cols opt ]]]]]]]]) | 存储过程 | N/A | 向数据库对象添加安全策略。 |
DROP_POLICY(object_schema, object_name, policy_name) | 存储过程 | N/A | 从数据库对象中删除安全策略。 |
ENABLE_POLICY(object_schema, object_name, policy_name, enable) | 存储过程 | N/A | 启用或禁用安全策略。 |
与Oracle版本的DBMS_RLS包执行相比,PolarDB的DBMS_RLS包执行是一个部分执行。PolarDB仅支持上述表中列出的函数和存储过程。
虚拟私有数据库是一种使用安全政策的细粒度访问控制。虚拟私有数据库中的细粒度访问控制意味着对于数据的访问可以控制到具体的行信息。
在policy function中定义了编码安全政策的规则。这个规则是一个SPL函数,有特定的输入参数和返回值。security policy是命名的政策函数联合到特定的数据库对象,尤其是表。
- 在PolarDB中,可以用任何PolarDB所支持的语言来编写政策函数。例如,除了与Oracle兼容的SPL语言外,您还可以使用SQL和PL/pgSQL语言。
- 目前PolarDB虚拟私有数据库所支持的数据库对象为表。政策不适用于视图或同义词。
- 虚拟私有数据库可以提供细粒度级别的安全访问。GRANT命令授予的数据库对象级别的权限能够决定访问权限是否能访问数据库对象中的整个实例。虚拟私有数据库则为数据库对象实例的个人记录提供了访问控制。
- 根据SQL命令(INSERT、UPDATE、DELETE或SELECT)的类型,您可以应用不同的安全政策。
- 由于每个可应用的SQL命令影响的数据库对象取决于一些因素(例如申请访问数据库对象的会话用户),因此安全政策会动态变化。
- 安全政策的调用对所有数据库对象的访问申请都是透明的。因此,您不用为了应用安全政策去修改个人申请。
- 一旦启用了安全政策,那么任何申请(包括新申请)都无法绕过安全政策。除下列说明中列出的系统权限以外。
- 除下列说明中列出的系统权限以外,即使是超级用户也不能绕过安全政策。
DBMS_RLS包提供的存储过程可用于创建、删除、启用及禁用安全政策。
- 首先要创建一个政策函数。这个函数必须有两个类型为VARCHAR2的输入参数。第一个输入参数提供给包含数据库对象(安全政策要应用于这个数据库对象上)的模式。第二个输入参数则提供给数据库对象的名称。所创建的这个政策函数还必须有一个VARCHAR2返回类型,且返回的必须是一个WHERE谓语子句形式的字符串。谓语将以AND条件动态附于对数据库对象起作用的SQL命令之上。因此,不满足政策函数谓语的记录将从SQL命令的结果集中过滤掉。
- 使用ADD_POLICY存储过程来定义一个新政策,这是政策函数与数据库对象的联合。通过使用ADD_POLICY存储过程,您可以指定SQL命令(例如:INSERT、 UPDATE、 DELETE或SELECT,且政策要应用于这些SQL命令之上)的类型,也可以决定是否在创建政策的同时对它进行启用,或决定政策函数是否可以应用于新插入的记录上或更新记录修改后的图像上。
- 使用ENABLE_POLICY存储过程来禁用或启用现有的安全政策。
- 使用DROP_POLICY存储过程来删除已有的政策。但DROP_POLICY存储过程不能删除政策函数或联合数据库对象。
一旦政策创建之后,您就可以在与Oracle兼容的目录视图下浏览所创建的政策。
SYS_CONTEXT(namespace, attribute)
namespace
是一个VARCHAR2值。唯一接受的值是USERENV。任何其他的值返回的都将是NULL。attribute
是一个VARCHAR2值。属性取值如下:属性值 等效值 SESSION_USER pg_catalog.session_user CURRENT_USER pg_catalog.current_user CURRENT_SCHEMA pg_catalog.current_schema HOST pg_catalog.inet_host IP_ADDRESS pg_catalog.inet_client_addr SERVER_HOST pg_catalog.inet_server_addr
CREATE TABLE public.vpemp AS SELECT empno, ename, job, sal, comm, deptno FROM emp;
ALTER TABLE vpemp ADD authid VARCHAR2(12);
UPDATE vpemp SET authid = 'researchmgr' WHERE deptno = 20;
UPDATE vpemp SET authid = 'salesmgr' WHERE deptno = 30;
SELECT * FROM vpemp;
empno | ename | job | sal | comm | deptno | authid
-------+--------+-----------+---------+---------+--------+-------------
7782 | CLARK | MANAGER | 2450.00 | | 10 |
7839 | KING | PRESIDENT | 5000.00 | | 10 |
7934 | MILLER | CLERK | 1300.00 | | 10 |
7369 | SMITH | CLERK | 800.00 | | 20 | researchmgr
7566 | JONES | MANAGER | 2975.00 | | 20 | researchmgr
7788 | SCOTT | ANALYST | 3000.00 | | 20 | researchmgr
7876 | ADAMS | CLERK | 1100.00 | | 20 | researchmgr
7902 | FORD | ANALYST | 3000.00 | | 20 | researchmgr
7499 | ALLEN | SALESMAN | 1600.00 | 300.00 | 30 | salesmgr
7521 | WARD | SALESMAN | 1250.00 | 500.00 | 30 | salesmgr
7654 | MARTIN | SALESMAN | 1250.00 | 1400.00 | 30 | salesmgr
7698 | BLAKE | MANAGER | 2850.00 | | 30 | salesmgr
7844 | TURNER | SALESMAN | 1500.00 | 0.00 | 30 | salesmgr
7900 | JAMES | CLERK | 950.00 | | 30 | salesmgr
(14 rows)
CREATE ROLE salesmgr WITH LOGIN PASSWORD 'password';
GRANT ALL ON vpemp TO salesmgr;
ADD_POLICY
ADD_POLICY存储过程通过联合政策函数和数据库对象来创建一个新政策。
只有超级用户才能执行ADD_POLICY存储过程。
ADD_POLICY(object_schema VARCHAR2, object_name VARCHAR2,
policy_name VARCHAR2, function_schema VARCHAR2,
policy_function VARCHAR2
[, statement_types VARCHAR2
[, update_check BOOLEAN
[, enable BOOLEAN
[, static_policy BOOLEAN
[, policy_type INTEGER
[, long_predicate BOOLEAN
[, sec_relevant_cols VARCHAR2
[, sec_relevant_cols_opt INTEGER ]]]]]]]])
参数
参数名称 | 描述 |
---|---|
object_schema | 包含数据库对象(政策将应用于这个数据库对象上)的模式名称。 |
object_name | 政策所要应用于的数据库对象的名称。也许会有1个以上的政策应用于一个指定的数据库对象上。 |
policy_name | 分配给政策的名称。数据库对象(由object_schema 和object_name 标识)的联接与政策名称在数据库中必须是唯一的。
|
function_schema | 包含政策函数的模式名称。
说明 政策函数也许属于一个包。在这种情况下,
function_schema 必须含有定义包的模式名称。
|
policy_function | SPL函数的名称,用于定义安全政策的规则。相同的函数也许会指定于多个政策中。
说明 政策函数也许属于一个包。在这种情况下,
policy_function 必须也包含点符号的包名称(也就是package_name . function_name )
|
statement_types | 逗号分隔的SQL命令列表,且政策应用于SQL命令之上。有效的SQL命令是INSERT、UPDATE、DELETE和SELECT 。默认为INSERT,UPDATE,DELETE,SELECT 。
说明 PolarDB接受INDEX为语句类型,但会忽略。在PolarDB中,政策不能应用于索引操作中。
|
update_check | update_check 只能应用于INSERT 和UPDATE 的SQL命令中。
|
enable |
|
static_policy |
说明
|
policy_type | 在Oracle环境下,policy_type 用于决定重新评估政策函数的时间。默认值为NULL。
说明 PolarDB仅执行动态政策,无需进行
policy_type 参数的设置。
|
longpredicate | 在Oracle环境下,如果将longpredicate 设置为TRUE,则允许谓语达到32KB字节。 否则,谓语就限制于4000字节。默认值为FALSE。
说明
longpredicate 参数的设置会被PolarDB忽略。一个PolarDB政策函数能返回一个对于所有实际用途不限长度的谓语。
|
sec_relevant_cols | sec_relevant_cols 是object_name 列的逗号分隔的列表。它可以给列出的列提供列级别的虚拟私有数据库。如果所列出的列引用于statement_types 中列出的SQL命令类型中,那么政策将被执行。如果没有引用这样的列,则不会执行政策。
默认值为NULL,默认值和 |
sec_relevant_cols_opt | 在Oracle环境下,如果将sec_relevant_cols_opt 设为DBMS_RLS.ALL_ROWS (INTEGER常量值1),那么在sec_relevant_cols 中列出的列就会返回所有记录的NULL值。其中,记录中应用的政策谓语为假。如果没有把sec_relevant_cols_opt 设为DBMS_RLS.ALL_ROWS ,那么结果集中将不会有这些记录返回。,默认值为NULL。
说明 PolarDB不支持
DBMS_RLS.ALL_ROWS 函数。如果将sec_relevant_cols_opt 设为DBMS_RLS.ALL_ROWS (INTEGER常量值1),那么PolarDB就会产生错误。
|
示例
CREATE OR REPLACE FUNCTION verify_session_user (
p_schema VARCHAR2,
p_object VARCHAR2
)
RETURN VARCHAR2
IS
BEGIN
RETURN 'authid = SYS_CONTEXT(''USERENV'', ''SESSION_USER'')';
END;
此函数产生的谓语authid = SYS_CONTEXT('USERENV', 'SESSION_USER')
被添加到在ADD_POLICY存储过程中指定类型的任何SQL命令的WHERE子句中。
此函数对那些列authid内容与会话用户相同的记录限制了SQL命令的结果。
下列匿名代码块调用了ADD_POLICY存储过程。从而创建名为secure_update的政策。 通过使用函数verify_session_user,可以把政策secure_update应用于表vpemp之上,即使在引用表vpemp时,是否给出了一个INSERT、 UPDATE或DELETE命令。
DECLARE
v_object_schema VARCHAR2(30) := 'public';
v_object_name VARCHAR2(30) := 'vpemp';
v_policy_name VARCHAR2(30) := 'secure_update';
v_function_schema VARCHAR2(30) := 'polardb';
v_policy_function VARCHAR2(30) := 'verify_session_user';
v_statement_types VARCHAR2(30) := 'INSERT,UPDATE,DELETE';
v_update_check BOOLEAN := TRUE;
v_enable BOOLEAN := TRUE;
BEGIN
DBMS_RLS.ADD_POLICY(
v_object_schema,
v_object_name,
v_policy_name,
v_function_schema,
v_policy_function,
v_statement_types,
v_update_check,
v_enable
);
END;
在成功创建政策之后,由用户salesmgr发起了一个终结会话。下列查询显示了表vpemp的内容。
\c polardb salesmgr
Password for user salesmgr:
You are now connected to database "polardb" as user "salesmgr".
SELECT * FROM vpemp;
empno | ename | job | sal | comm | deptno | authid
-------+--------+-----------+---------+---------+--------+-------------
7782 | CLARK | MANAGER | 2450.00 | | 10 |
7839 | KING | PRESIDENT | 5000.00 | | 10 |
7934 | MILLER | CLERK | 1300.00 | | 10 |
7369 | SMITH | CLERK | 800.00 | | 20 | researchmgr
7566 | JONES | MANAGER | 2975.00 | | 20 | researchmgr
7788 | SCOTT | ANALYST | 3000.00 | | 20 | researchmgr
7876 | ADAMS | CLERK | 1100.00 | | 20 | researchmgr
7902 | FORD | ANALYST | 3000.00 | | 20 | researchmgr
7499 | ALLEN | SALESMAN | 1600.00 | 300.00 | 30 | salesmgr
7521 | WARD | SALESMAN | 1250.00 | 500.00 | 30 | salesmgr
7654 | MARTIN | SALESMAN | 1250.00 | 1400.00 | 30 | salesmgr
7698 | BLAKE | MANAGER | 2850.00 | | 30 | salesmgr
7844 | TURNER | SALESMAN | 1500.00 | 0.00 | 30 | salesmgr
7900 | JAMES | CLERK | 950.00 | | 30 | salesmgr
(14 rows)
用户salesmgr发起了一个非模式限定的UPDATE命令(没有WHERE子句):
UPDATE vpemp SET comm = sal * .75;
UPDATE 6
政策不会更新表中所有的记录,而是仅对那些authid列中含有salesmgr的记录限制更新结果。其中,salesmgr值是由政策函数谓语authid = SYS_CONTEXT('USERENV', 'SESSION_USER')
指定的。
下列查询结果显示了comm列仅为那些authid列中含有salesmgr的记录而进行改变。所有其他的记录不变 。
SELECT * FROM vpemp;
empno | ename | job | sal | comm | deptno | authid
-------+--------+-----------+---------+---------+--------+-------------
7782 | CLARK | MANAGER | 2450.00 | | 10 |
7839 | KING | PRESIDENT | 5000.00 | | 10 |
7934 | MILLER | CLERK | 1300.00 | | 10 |
7369 | SMITH | CLERK | 800.00 | | 20 | researchmgr
7566 | JONES | MANAGER | 2975.00 | | 20 | researchmgr
7788 | SCOTT | ANALYST | 3000.00 | | 20 | researchmgr
7876 | ADAMS | CLERK | 1100.00 | | 20 | researchmgr
7902 | FORD | ANALYST | 3000.00 | | 20 | researchmgr
7499 | ALLEN | SALESMAN | 1600.00 | 1200.00 | 30 | salesmgr
7521 | WARD | SALESMAN | 1250.00 | 937.50 | 30 | salesmgr
7654 | MARTIN | SALESMAN | 1250.00 | 937.50 | 30 | salesmgr
7698 | BLAKE | MANAGER | 2850.00 | 2137.50 | 30 | salesmgr
7844 | TURNER | SALESMAN | 1500.00 | 1125.00 | 30 | salesmgr
7900 | JAMES | CLERK | 950.00 | 712.50 | 30 | salesmgr
(14 rows)
由于在ADD_POLICY存储过程中将update_check
参数设为TRUE,所以下列INSERT命令会产生异常。 且由于给列authid的researchmgr值与会话用户salesmgr不匹配,所以使政策失效。
INSERT INTO vpemp VALUES (9001,'SMITH','ANALYST',3200.00,NULL,20, 'researchmgr');
ERROR: policy with check option violation
DETAIL: Policy predicate was evaluated to FALSE with the updated values
如果您将update_check
设为FALSE,上面描述的INSERT命令就会生效。
下列示例说明了要应用于政策的sec_relevant_cols
参数仅在SQL命令中引用特定列时使用。示例中的政策函数选择了员工薪水少于2000的记录。
CREATE OR REPLACE FUNCTION sal_lt_2000 (
p_schema VARCHAR2,
p_object VARCHAR2
)
RETURN VARCHAR2
IS
BEGIN
RETURN 'sal < 2000';
END;
创建政策是为了在SELECT命令包括sal或comm列时,执行所创建的政策:
DECLARE
v_object_schema VARCHAR2(30) := 'public';
v_object_name VARCHAR2(30) := 'vpemp';
v_policy_name VARCHAR2(30) := 'secure_salary';
v_function_schema VARCHAR2(30) := 'polardb';
v_policy_function VARCHAR2(30) := 'sal_lt_2000';
v_statement_types VARCHAR2(30) := 'SELECT';
v_sec_relevant_cols VARCHAR2(30) := 'sal,comm';
BEGIN
DBMS_RLS.ADD_POLICY(
v_object_schema,
v_object_name,
v_policy_name,
v_function_schema,
v_policy_function,
v_statement_types,
sec_relevant_cols => v_sec_relevant_cols
);
END;
如果一个查询没有引用列sal或comm,即没有应用政策。下列查询返回的是表vpemp的14行记录:
SELECT empno, ename, job, deptno, authid FROM vpemp;
empno | ename | job | deptno | authid
-------+--------+-----------+--------+-------------
7782 | CLARK | MANAGER | 10 |
7839 | KING | PRESIDENT | 10 |
7934 | MILLER | CLERK | 10 |
7369 | SMITH | CLERK | 20 | researchmgr
7566 | JONES | MANAGER | 20 | researchmgr
7788 | SCOTT | ANALYST | 20 | researchmgr
7876 | ADAMS | CLERK | 20 | researchmgr
7902 | FORD | ANALYST | 20 | researchmgr
7499 | ALLEN | SALESMAN | 30 | salesmgr
7521 | WARD | SALESMAN | 30 | salesmgr
7654 | MARTIN | SALESMAN | 30 | salesmgr
7698 | BLAKE | MANAGER | 30 | salesmgr
7844 | TURNER | SALESMAN | 30 | salesmgr
7900 | JAMES | CLERK | 30 | salesmgr
(14 rows)
如果查询引用了列sal或comm,这个查询则应用了政策。然后这个查询删除了任何sal大于或等于2000的记录。如下所示:
SELECT empno, ename, job, sal, comm, deptno, authid FROM vpemp;
empno | ename | job | sal | comm | deptno | authid
-------+--------+----------+---------+---------+--------+-------------
7934 | MILLER | CLERK | 1300.00 | | 10 |
7369 | SMITH | CLERK | 800.00 | | 20 | researchmgr
7876 | ADAMS | CLERK | 1100.00 | | 20 | researchmgr
7499 | ALLEN | SALESMAN | 1600.00 | 1200.00 | 30 | salesmgr
7521 | WARD | SALESMAN | 1250.00 | 937.50 | 30 | salesmgr
7654 | MARTIN | SALESMAN | 1250.00 | 937.50 | 30 | salesmgr
7844 | TURNER | SALESMAN | 1500.00 | 1125.00 | 30 | salesmgr
7900 | JAMES | CLERK | 950.00 | 712.50 | 30 | salesmgr
(8 rows)
DROP_POLICY
DROP_POLICY(object_schema VARCHAR2, object_name VARCHAR2,
policy_name VARCHAR2)
参数
参数名称 | 描述 |
---|---|
object_schema | 数据库对象(政策应用于此数据库对象之上)的模式名称。 |
object_name | 数据库对象(政策应用于此数据库对象之上)的名称。 |
policy_name | 要删除的政策名称。 |
示例
下列示例删除了应用于表public. Vpemp的secure_update政策:
DECLARE
v_object_schema VARCHAR2(30) := 'public';
v_object_name VARCHAR2(30) := 'vpemp';
v_policy_name VARCHAR2(30) := 'secure_update';
BEGIN
DBMS_RLS.DROP_POLICY(
v_object_schema,
v_object_name,
v_policy_name
);
END;
ENABLE_POLICY
ENABLE_POLICY(object_schema VARCHAR2, object_name VARCHAR2,
policy_name VARCHAR2, enable BOOLEAN)
参数
参数名称 | 描述 |
---|---|
object schema | 数据库对象(政策应用于此数据库对象之上)的模式名称。 |
object name | 数据库对象(政策应用于此数据库对象之上)的名称。 |
policy name | 要启用或禁用的政策名称。 |
enable | 启用或禁用政策。
|
示例
下列示例禁用了表public .vpemp上的secure_update政策:
DECLARE
v_object_schema VARCHAR2(30) := 'public';
v_object_name VARCHAR2(30) := 'vpemp';
v_policy_name VARCHAR2(30) := 'secure_update';
v_enable BOOLEAN := FALSE;
BEGIN
DBMS_RLS.ENABLE_POLICY(
v_object_schema,
v_object_name,
v_policy_name,
v_enable
);
END;