您的位置:首页 > 数据库 > Oracle

oracle VPD

2016-01-28 23:01 489 查看

原文链接: http://blog.csdn.net/chncaesar/article/details/18550029
VPD = Virtual Private Database。同义词有RLS : Row Level Security, FGAC: Fine Grained Access Control。

用于行级访问控制。假设有需求,只有用户'SCOTT'能访问emp表所有记录,其他人只能访问manager以下员工的记录。

[sql]
view plaincopyprint?





CREATE FUNCTION emp_policy(schema_in IN VARCHAR2,object_in IN VARCHAR2)  
RETURN VARCHAR2  
IS  
  l_return_value VARCHAR2(32767);  
BEGIN  
 IF SYS_CONTEXT('USERENV', 'SESSION_USER') = 'SCOTT' THEN  
    l_return_value := '1=1';  
 ELSE  
    l_return_value := 'JOB NOT IN (''PRESIDENT'',''MANAGER'')';  
 END IF;   
 RETURN l_return_value;  
END;  
  
BEGIN  
  DBMS_RLS.ADD_POLICY (  
    object_schema    => 'SCOTT',  
    object_name      => 'EMP',  
    policy_name      => 'EMP_POLICY',  
    function_schema  => 'SCOTT',  
    policy_function  => 'emp_policy',  
    statement_types  => 'SELECT, INSERT, UPDATE, DELETE'  
   );  
END;  

CREATE FUNCTION emp_policy(schema_in IN VARCHAR2,object_in IN VARCHAR2)
RETURN VARCHAR2
IS
l_return_value VARCHAR2(32767);
BEGIN
IF SYS_CONTEXT('USERENV', 'SESSION_USER') = 'SCOTT' THEN
l_return_value := '1=1';
ELSE
l_return_value := 'JOB NOT IN (''PRESIDENT'',''MANAGER'')';
END IF;
RETURN l_return_value;
END;

BEGIN
DBMS_RLS.ADD_POLICY (
object_schema    => 'SCOTT',
object_name      => 'EMP',
policy_name      => 'EMP_POLICY',
function_schema  => 'SCOTT',
policy_function  => 'emp_policy',
statement_types  => 'SELECT, INSERT, UPDATE, DELETE'
);
END;
控制访问权限的函数-emp_policy有特定的声明,如上所示,它的返回值是where语句部分。对于scott.emp表的select/insert/update/delete,Oracle将自动将l_return_value加入where部分。

我们测试一下:

[sql]
view plaincopyprint?





[oracle@odilab ~]$ sqlplus scott/a123456  
  
SQL*Plus: Release 11.2.0.1.0 Production on Sun Jan 19 22:52:20 2014  
  
Copyright (c) 1982, 2009, Oracle.  All rights reserved.  
  
  
Connected to:  
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production  
With the Partitioning, OLAP, Data Mining and Real Application Testing options  
  
$scott@ORCL> select * from emp;  
  
     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM     DEPTNO  
---------- ---------- --------- ---------- --------- ---------- ---------- ----------  
      7935 HUIYE      PRESIDENT (null)     03-NOV-13       9999 (null)             10  
      7369 SMITH      CLERK           7902 17-DEC-80        800 (null)             20  
      7499 ALLEN      SALESMAN        7698 20-FEB-81       1600        300         30  
      7521 WARD       SALESMAN        7698 22-FEB-81       1250        500         30  
      7566 JONES      MANAGER         7839 02-APR-81       2975 (null)             20  
      7654 MARTIN     SALESMAN        7698 28-SEP-81       1250       1400         30  
      7698 BLAKE      MANAGER         7839 01-MAY-81       2850 (null)             30  
      7782 CLARK      MANAGER         7839 09-JUN-81       2450 (null)             10  
      7788 SCOTT      ANALYST         7566 19-APR-87       3000 (null)             20  
      7839 KING       PRESIDENT (null)     17-NOV-81       5000 (null)             10  
      7844 TURNER     SALESMAN        7698 08-SEP-81       1500          0         30  
      7876 ADAMS      CLERK           7788 23-MAY-87       1100 (null)             20  
      7900 JAMES      CLERK           7698 03-DEC-81        950 (null)             30  
      7902 FORD       ANALYST         7566 03-DEC-81       3000 (null)             20  
      7934 MILLER     CLERK           7782 23-JAN-82       1300 (null)   
1a5e9
          10  
  
15 rows selected.  
$scott@ORCL> connect scott1/a123456  
Connected.  
  
$scott1@ORCL> select * from scott.emp;  
  
     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM     DEPTNO  
---------- ---------- --------- ---------- --------- ---------- ---------- ----------  
      7369 SMITH      CLERK           7902 17-DEC-80        800 (null)             20  
      7499 ALLEN      SALESMAN        7698 20-FEB-81       1600        300         30  
      7521 WARD       SALESMAN        7698 22-FEB-81       1250        500         30  
      7654 MARTIN     SALESMAN        7698 28-SEP-81       1250       1400         30  
      7788 SCOTT      ANALYST         7566 19-APR-87       3000 (null)             20  
      7844 TURNER     SALESMAN        7698 08-SEP-81       1500          0         30  
      7876 ADAMS      CLERK           7788 23-MAY-87       1100 (null)             20  
      7900 JAMES      CLERK           7698 03-DEC-81        950 (null)             30  
      7902 FORD       ANALYST         7566 03-DEC-81       3000 (null)             20  
      7934 MILLER     CLERK           7782 23-JAN-82       1300 (null)             10  
  
10 rows selected.  

[oracle@odilab ~]$ sqlplus scott/a123456

SQL*Plus: Release 11.2.0.1.0 Production on Sun Jan 19 22:52:20 2014

Copyright (c) 1982, 2009, Oracle.  All rights reserved.

Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

$scott@ORCL> select * from emp;

EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM     DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
7935 HUIYE      PRESIDENT (null)     03-NOV-13       9999 (null)             10
7369 SMITH      CLERK           7902 17-DEC-80        800 (null)             20
7499 ALLEN      SALESMAN        7698 20-FEB-81       1600        300         30
7521 WARD       SALESMAN        7698 22-FEB-81       1250        500         30
7566 JONES      MANAGER         7839 02-APR-81       2975 (null)             20
7654 MARTIN     SALESMAN        7698 28-SEP-81       1250       1400         30
7698 BLAKE      MANAGER         7839 01-MAY-81       2850 (null)             30
7782 CLARK      MANAGER         7839 09-JUN-81       2450 (null)             10
7788 SCOTT      ANALYST         7566 19-APR-87       3000 (null)             20
7839 KING       PRESIDENT (null)     17-NOV-81       5000 (null)             10
7844 TURNER     SALESMAN        7698 08-SEP-81       1500          0         30
7876 ADAMS      CLERK           7788 23-MAY-87       1100 (null)             20
7900 JAMES      CLERK           7698 03-DEC-81        950 (null)             30
7902 FORD       ANALYST         7566 03-DEC-81       3000 (null)             20
7934 MILLER     CLERK           7782 23-JAN-82       1300 (null)             10

15 rows selected.
$scott@ORCL> connect scott1/a123456
Connected.

$scott1@ORCL> select * from scott.emp;

EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM     DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
7369 SMITH      CLERK           7902 17-DEC-80        800 (null)             20
7499 ALLEN      SALESMAN        7698 20-FEB-81       1600        300         30
7521 WARD       SALESMAN        7698 22-FEB-81       1250        500         30
7654 MARTIN     SALESMAN        7698 28-SEP-81       1250       1400         30
7788 SCOTT      ANALYST         7566 19-APR-87       3000 (null)             20
7844 TURNER     SALESMAN        7698 08-SEP-81       1500          0         30
7876 ADAMS      CLERK           7788 23-MAY-87       1100 (null)             20
7900 JAMES      CLERK           7698 03-DEC-81        950 (null)             30
7902 FORD       ANALYST         7566 03-DEC-81       3000 (null)             20
7934 MILLER     CLERK           7782 23-JAN-82       1300 (null)             10

10 rows selected.

我们也可以在session中声明自己的context,并给context赋值,最终由context中的值决定l_return_value。如下所示:

[sql]
view plaincopyprint?





CREATE OR REPLACE CONTEXT MY_CONTEXT USING MY_CONTEXT_PKG;  
CREATE OR REPLACE PACKAGE my_context_pkg IS  
 PROCEDURE SET_MAX_DEPT;  
END MY_CONTEXT_PKG;  
  
CREATE OR REPLACE PACKAGE BODY my_context_pkg IS  
 PROCEDURE set_max_dept  
 AS  
    l_max_deptno NUMBER;  
 BEGIN  
   CASE SYS_CONTEXT('USERENV', 'SESSION_USER')  
     WHEN 'SCOTT' THEN l_max_deptno := 9999;  
     WHEN 'HR' THEN l_max_deptno := 10;  
     WHEN 'OE' THEN l_max_deptno := 20;  
     ELSE l_max_deptno := 0;  
   END CASE;  
   DBMS_SESSION.SET_CONTEXT('my_context', 'max_deptno', l_max_deptno);  
 END set_max_dept;  
END my_context_pkg;  
  
CREATE TRIGGER tr_set_max_dept AFTER LOGON ON DATABASE  
BEGIN  
    scott.my_context_pkg.set_max_dept;  
END;  
  
CREATE FUNCTION DEPT_POLICY(SCHEMA_IN IN VARCHAR2,OBJECT_IN IN VARCHAR2)  
RETURN VARCHAR2  
IS  
  l_return_value VARCHAR2 (32767);  
 BEGIN  
  CASE SYS_CONTEXT('my_context', 'max_deptno')  
    WHEN 10 THEN l_return_value := 'DEPTNO <= 10';  
    WHEN 20 THEN l_return_value := 'DEPTNO <= 20';  
    WHEN 30 THEN l_return_value := 'DEPTNO <= 30';  
    WHEN 40 THEN l_return_value := 'DEPTNO <= 40';  
    WHEN 9999 THEN l_return_value := '1=1';  
    ELSE l_return_value := '1=0';  
  END IF;  
  RETURN L_RETURN_VALUE;  
END MY_POLICY;  

CREATE OR REPLACE CONTEXT MY_CONTEXT USING MY_CONTEXT_PKG;
CREATE OR REPLACE PACKAGE my_context_pkg IS
PROCEDURE SET_MAX_DEPT;
END MY_CONTEXT_PKG;

CREATE OR REPLACE PACKAGE BODY my_context_pkg IS
PROCEDURE set_max_dept
AS
l_max_deptno NUMBER;
BEGIN
CASE SYS_CONTEXT('USERENV', 'SESSION_USER')
WHEN 'SCOTT' THEN l_max_deptno := 9999;
WHEN 'HR' THEN l_max_deptno := 10;
WHEN 'OE' THEN l_max_deptno := 20;
ELSE l_max_deptno := 0;
END CASE;
DBMS_SESSION.SET_CONTEXT('my_context', 'max_deptno', l_max_deptno);
END set_max_dept;
END my_context_pkg;

CREATE TRIGGER tr_set_max_dept AFTER LOGON ON DATABASE
BEGIN
scott.my_context_pkg.set_max_dept;
END;

CREATE FUNCTION DEPT_POLICY(SCHEMA_IN IN VARCHAR2,OBJECT_IN IN VARCHAR2)
RETURN VARCHAR2
IS
l_return_value VARCHAR2 (32767);
BEGIN
CASE SYS_CONTEXT('my_context', 'max_deptno')
WHEN 10 THEN l_return_value := 'DEPTNO <= 10';
WHEN 20 THEN l_return_value := 'DEPTNO <= 20';
WHEN 30 THEN l_return_value := 'DEPTNO <= 30';
WHEN 40 THEN l_return_value := 'DEPTNO <= 40';
WHEN 9999 THEN l_return_value := '1=1';
ELSE l_return_value := '1=0';
END IF;
RETURN L_RETURN_VALUE;
END MY_POLICY;


查询和删除policy

dba|all|user_policies视图保存了与VPD相关的policy

[sql]
view plaincopyprint?





select object_owner, object_name, policy_name, pf_owner, function, enable, static_policy, policy_type  
from all_policies;  

select object_owner, object_name, policy_name, pf_owner, function, enable, static_policy, policy_type
from all_policies;


[sql]
view plaincopyprint?





DBMS_RLS.DROP_POLICY (object_schema IN VARCHAR2 NULL, object_name in varchar2,policy_name IN VARCHAR2);  

DBMS_RLS.DROP_POLICY (object_schema IN VARCHAR2 NULL, object_name in varchar2,policy_name IN VARCHAR2);
可以删除某个policy。

Add_policy的Policy_type参数

STATIC - The return value of the policy function is cached and reused repeatedly for an individual object. By definition thereturn value of the policy function must be static.
SHARED_STATIC - The same as STATIC but the resulting predicate can be applied to several objects.
CONTEXT_SENSITIVE - Used when policy is based around local application context. The result of the policy function is cached and reused. The policy function is only executed again when the value of the application context changes.
SHARED_CONTEXT_SENSITIVE - The same as CONTEXT_SENSITIVE but the resulting predicate can be applied to several objects.
DYNAMIC - The policy function is executed for every SQL statement.
Static and dynamic policy function被调用次数

[sql]
view plaincopyprint?





create or replace function dept_policy(schema_in in varchar2,object_in in varchar2)  
RETURN VARCHAR2  
IS    
begin  
 dbms_application_info.set_client_info(userenv('client_info')+1);   
 RETURN '1=1';  
END;  
  
exec dbms_rls.drop_policy('SCOTT','DEPT','DEPT_POLICY');  
BEGIN  
 DBMS_RLS.ADD_POLICY (  
    object_schema    => 'SCOTT',  
    object_name      => 'DEPT',  
    policy_name      => 'DEPT_POLICY',  
    function_schema  => 'SCOTT',  
    policy_function  => 'DEPT_policy',  
    statement_types  => 'SELECT, INSERT, UPDATE, DELETE',  
    policy_type => dbms_rls.dynamic --  
   );  
END;  
$scott@ORCL> select policy_name, function, enable, static_policy, policy_type from all_policies;  
  
  
POLICY_NAME                    FUNCTION                       ENA STA POLICY_TYPE  
------------------------------ ------------------------------ --- --- ------------------------  
DEPT_POLICY                    DEPT_POLICY                    YES NO  DYNAMIC  
EMP_POLICY                     EMP_POLICY                     YES NO  DYNAMIC  
  
exec dbms_application_info.set_client_info(0);   
select /*my4*/ * from dept;  
select userenv('client_info') from dual;  

create or replace function dept_policy(schema_in in varchar2,object_in in varchar2)
RETURN VARCHAR2
IS
begin
dbms_application_info.set_client_info(userenv('client_info')+1);
RETURN '1=1';
END;

exec dbms_rls.drop_policy('SCOTT','DEPT','DEPT_POLICY');
BEGIN
DBMS_RLS.ADD_POLICY (
object_schema    => 'SCOTT',
object_name      => 'DEPT',
policy_name      => 'DEPT_POLICY',
function_schema  => 'SCOTT',
policy_function  => 'DEPT_policy',
statement_types  => 'SELECT, INSERT, UPDATE, DELETE',
policy_type => dbms_rls.dynamic --
);
END;
$scott@ORCL> select policy_name, function, enable, static_policy, policy_type from all_policies;

POLICY_NAME                    FUNCTION                       ENA STA POLICY_TYPE
------------------------------ ------------------------------ --- --- ------------------------
DEPT_POLICY                    DEPT_POLICY                    YES NO  DYNAMIC
EMP_POLICY                     EMP_POLICY                     YES NO  DYNAMIC

exec dbms_application_info.set_client_info(0); 
select /*my4*/ * from dept;
select userenv('client_info') from dual;

Policy_Type为dynamic时,每次执行这条Query返回20条记录,调用2次policy function - dept_policy。根据Oracle文档每次SQL parse和execution各调用一次policy function。

同样的policy_function,假如在add_policy时policy_type => dbms_rls.static时。同样的Query也会返回20条记录,第一次执行调用一次policy function,以后不再调用,因为policy function的结果缓存在SGA中。这符合我们的预期。

Static

static要求policy function返回值是一个常量,考虑如下VPD配置:

[sql]
view plaincopyprint?





CREATE OR REPLACE FUNCTION EMP_POLICY(P_SCHEMA IN VARCHAR2, P_OBJECT IN VARCHAR2)  
RETURN VARCHAR2  
IS  
BEGIN  
  dbms_application_info.set_client_info(userenv('client_info')+1);  
  RETURN 'ename = SYS_CONTEXT (''USERENV'', ''SESSION_USER'')';  
END;  
  
BEGIN    
  DBMS_RLS.ADD_POLICY (    
    object_schema    => 'SCOTT',    
    object_name      => 'EMP',    
    policy_name      => 'EMP_POLICY',    
    function_schema  => 'SCOTT',    
    POLICY_FUNCTION  => 'emp_policy',    
    STATEMENT_TYPES  => 'SELECT, INSERT, UPDATE, DELETE',  
    policy_type => dbms_rls.static  
   );    
END;  
Elapsed: 00:00:00.01  
$clark@ORCL> select ename from scott.emp;  
  
ENAME  
----------  
CLARK  
  
Elapsed: 00:00:00.00  
$clark@ORCL> connect scott/xxx  
Connected.  
$scott@ORCL> select ename from scott.emp;  
  
ENAME  
----------  
SCOTT  
  
Elapsed: 00:00:00.01  
SQL_ID  5nwx8yqg94xdy, child number 1  
-------------------------------------  
select ename from scott.emp  
   
Plan hash value: 3956160932  
   
--------------------------------------------------------------------------  
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |  
--------------------------------------------------------------------------  
|   0 | SELECT STATEMENT  |      |       |       |     3 (100)|          |  
|*  1 |  TABLE ACCESS FULL| EMP  |     1 |     6 |     3   (0)| 00:00:01 |  
--------------------------------------------------------------------------  
   
Predicate Information (identified by operation id):  
---------------------------------------------------  
   
   1 - filter("ENAME"=SYS_CONTEXT('USERENV','SESSION_USER'))  

CREATE OR REPLACE FUNCTION EMP_POLICY(P_SCHEMA IN VARCHAR2, P_OBJECT IN VARCHAR2)
RETURN VARCHAR2
IS
BEGIN
dbms_application_info.set_client_info(userenv('client_info')+1);
RETURN 'ename = SYS_CONTEXT (''USERENV'', ''SESSION_USER'')';
END;

BEGIN
DBMS_RLS.ADD_POLICY (
object_schema    => 'SCOTT',
object_name      => 'EMP',
policy_name      => 'EMP_POLICY',
function_schema  => 'SCOTT',
POLICY_FUNCTION  => 'emp_policy',
STATEMENT_TYPES  => 'SELECT, INSERT, UPDATE, DELETE',
policy_type => dbms_rls.static
);
END;
Elapsed: 00:00:00.01
$clark@ORCL> select ename from scott.emp;

ENAME
----------
CLARK

Elapsed: 00:00:00.00
$clark@ORCL> connect scott/xxx
Connected.
$scott@ORCL> select ename from scott.emp;

ENAME
----------
SCOTT

Elapsed: 00:00:00.01
SQL_ID  5nwx8yqg94xdy, child number 1
-------------------------------------
select ename from scott.emp

Plan hash value: 3956160932

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |       |       |     3 (100)|          |
|*  1 |  TABLE ACCESS FULL| EMP  |     1 |     6 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - filter("ENAME"=SYS_CONTEXT('USERENV','SESSION_USER'))
结论:这种场景,static vpd policy是可行的。

Column level security

有个需求:emp表中dept=10(总裁们所在部门)的工资信息不希望被查询到。

[sql]
view plaincopyprint?





CREATE OR REPLACE FUNCTION EMP_POLICY(P_SCHEMA IN VARCHAR2, P_OBJECT IN VARCHAR2)  
RETURN VARCHAR2  
IS  
BEGIN  
  DBMS_APPLICATION_INFO.SET_CLIENT_INFO(USERENV('client_info')+1);  
  RETURN 'deptno=10';  
END;  
  
BEGIN    
  DBMS_RLS.ADD_POLICY (    
    object_schema    => 'SCOTT',    
    object_name      => 'EMP',    
    policy_name      => 'EMP_POLICY',    
    function_schema  => 'SCOTT',    
    POLICY_FUNCTION  => 'emp_policy',    
    STATEMENT_TYPES  => 'SELECT, INSERT, UPDATE, DELETE',  
    POLICY_TYPE => DBMS_RLS.STATIC,  
    sec_relevant_cols => 'sal'  
   );    
END;  
$scott@ORCL> select deptno, ename, sal from emp;  
  
    DEPTNO ENAME             SAL  
---------- ---------- ----------  
        20 SMITH             800  
        20 JONES            2975  
        20 SCOTT            3000  
        20 ADAMS            1100  
        20 FORD             3000  
  
Elapsed: 00:00:00.00  
$scott@ORCL> select deptno, ename from emp;  
  
    DEPTNO ENAME  
---------- ----------  
        10 HUIYE  
        20 SMITH  
        30 ALLEN  
        30 WARD  
        20 JONES  
        30 MARTIN  
        30 BLAKE  
        10 CLARK  
        20 SCOTT  
        10 KING  
        30 TURNER  
        20 ADAMS  
        30 JAMES  
        20 FORD  
        10 MILLER  
  
15 rows selected.  
  
Elapsed: 00:00:00.01  

CREATE OR REPLACE FUNCTION EMP_POLICY(P_SCHEMA IN VARCHAR2, P_OBJECT IN VARCHAR2)
RETURN VARCHAR2
IS
BEGIN
DBMS_APPLICATION_INFO.SET_CLIENT_INFO(USERENV('client_info')+1);
RETURN 'deptno=10';
END;

BEGIN
DBMS_RLS.ADD_POLICY (
object_schema    => 'SCOTT',
object_name      => 'EMP',
policy_name      => 'EMP_POLICY',
function_schema  => 'SCOTT',
POLICY_FUNCTION  => 'emp_policy',
STATEMENT_TYPES  => 'SELECT, INSERT, UPDATE, DELETE',
POLICY_TYPE => DBMS_RLS.STATIC,
sec_relevant_cols => 'sal'
);
END;
$scott@ORCL> select deptno, ename, sal from emp;

DEPTNO ENAME             SAL
---------- ---------- ----------
20 SMITH             800
20 JONES            2975
20 SCOTT            3000
20 ADAMS            1100
20 FORD             3000

Elapsed: 00:00:00.00
$scott@ORCL> select deptno, ename from emp;

DEPTNO ENAME
---------- ----------
10 HUIYE
20 SMITH
30 ALLEN
30 WARD
20 JONES
30 MARTIN
30 BLAKE
10 CLARK
20 SCOTT
10 KING
30 TURNER
20 ADAMS
30 JAMES
20 FORD
10 MILLER

15 rows selected.

Elapsed: 00:00:00.01

可以看到,只要用户试图查找deptno=10的员工的薪水,那么deptno=10的行就不显示。也就是说,用户查询sal时,policy function给出的predicate就会被加到sql中。

Data Masking

[sql]
view plaincopyprint?





CREATE OR REPLACE FUNCTION EMP_POLICY(P_SCHEMA IN VARCHAR2, P_OBJECT IN VARCHAR2)  
RETURN VARCHAR2  
IS  
BEGIN  
  DBMS_APPLICATION_INFO.SET_CLIENT_INFO(USERENV('client_info')+1);  
  RETURN 'deptno=10';  
END;  
  
BEGIN    
  DBMS_RLS.ADD_POLICY (  
    object_schema    => 'SCOTT',    
    object_name      => 'EMP',    
    policy_name      => 'EMP_POLICY',    
    function_schema  => 'SCOTT',    
    POLICY_FUNCTION  => 'emp_policy',      
    POLICY_TYPE => DBMS_RLS.STATIC,  
    SEC_RELEVANT_COLS => 'sal',  
    sec_relevant_cols_opt => DBMS_RLS.ALL_ROWS  
   );    
END;  
  
$scott@ORCL> select deptno, ename, sal from emp order by deptno;  
  
    DEPTNO ENAME             SAL  
---------- ---------- ----------  
        10 HUIYE            9999  
        10 MILLER           1300  
        10 KING             5000  
        10 CLARK            2450  
        20 JONES      (null)  
        20 SMITH      (null)  
        20 FORD       (null)  
        20 ADAMS      (null)  
        20 SCOTT      (null)  
        30 ALLEN      (null)  
        30 TURNER     (null)  
        30 JAMES      (null)  
        30 WARD       (null)  
        30 BLAKE      (null)  
        30 MARTIN     (null)  

CREATE OR REPLACE FUNCTION EMP_POLICY(P_SCHEMA IN VARCHAR2, P_OBJECT IN VARCHAR2)
RETURN VARCHAR2
IS
BEGIN
DBMS_APPLICATION_INFO.SET_CLIENT_INFO(USERENV('client_info')+1);
RETURN 'deptno=10';
END;

BEGIN
DBMS_RLS.ADD_POLICY (
object_schema    => 'SCOTT',
object_name      => 'EMP',
policy_name      => 'EMP_POLICY',
function_schema  => 'SCOTT',
POLICY_FUNCTION  => 'emp_policy',
POLICY_TYPE => DBMS_RLS.STATIC,
SEC_RELEVANT_COLS => 'sal',
sec_relevant_cols_opt => DBMS_RLS.ALL_ROWS
);
END;

$scott@ORCL> select deptno, ename, sal from emp order by deptno;

DEPTNO ENAME             SAL
---------- ---------- ----------
10 HUIYE            9999
10 MILLER           1300
10 KING             5000
10 CLARK            2450
20 JONES      (null)
20 SMITH      (null)
20 FORD       (null)
20 ADAMS      (null)
20 SCOTT      (null)
30 ALLEN      (null)
30 TURNER     (null)
30 JAMES      (null)
30 WARD       (null)
30 BLAKE      (null)
30 MARTIN     (null)

可以看到deptno=10的员工的薪水照常显示,其他部门的都显示为null。 看来,data masking不作用于policy function返回的predicate包含的数据。

VPD的性能

测试了三种情况:

不使用VPD,SQL手工添加predicate再执行
使用VPD,policy_type=static
使用VPD,policy_type=dynamic

Policy function如下:

[sql]
view plaincopyprint?





create or replace FUNCTION EMP_POLICY_1(P_SCHEMA IN VARCHAR2, P_OBJECT IN VARCHAR2)    
RETURN VARCHAR2    
IS    
BEGIN    
  dbms_application_info.set_client_info(userenv('client_info')+1);    
  RETURN 'deptno = SYS_CONTEXT (''my_context'', ''deptno'')';  
end;    

create or replace FUNCTION EMP_POLICY_1(P_SCHEMA IN VARCHAR2, P_OBJECT IN VARCHAR2)
RETURN VARCHAR2
IS
BEGIN
dbms_application_info.set_client_info(userenv('client_info')+1);
RETURN 'deptno = SYS_CONTEXT (''my_context'', ''deptno'')';
end;
application context: my_context.deptno的值由trigger设置,具体方法参考上文。

下面给出三次测试的执行计划:

[sql]
view plaincopyprint?





SQL_ID  cj605kcb4s1t6, child number 0  
-------------------------------------  
select /*3*/ count(*) from emp2 where   
deptno=sys_context('my_context','deptno')  
   
Plan hash value: 2889146209  
   
------------------------------------------------------------------------------------------------------------------------------  
| Id  | Operation          | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers | Reads  |  
------------------------------------------------------------------------------------------------------------------------------  
|   0 | SELECT STATEMENT   |      |      1 |        |       | 37905 (100)|          |      1 |00:00:20.14 |     137K|    137K|  
|   1 |  SORT AGGREGATE    |      |      1 |      1 |     3 |            |          |      1 |00:00:20.14 |     137K|    137K|  
|*  2 |   TABLE ACCESS FULL| EMP2 |      1 |   2857K|  8370K| 37905   (2)| 00:07:35 |   1998K|00:00:10.93 |     137K|    137K|  
------------------------------------------------------------------------------------------------------------------------------  
   
Predicate Information (identified by operation id):  
---------------------------------------------------  
   
   2 - filter("DEPTNO"=TO_NUMBER(SYS_CONTEXT('my_context','deptno')))  
   
  
<pre class="sql" name="code" snippet_file_name="blog_20140125_11_4161141" code_snippet_id="163969">------------dynamic------------</pre> SQL_ID 39sknfv3wmb37, child number 0 select /*3*/ count(*) from emp0 Plan hash value: 3474440072 ------------------------------------------------------------------------------------------------------------------------------| Id | Operation  
 | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers | Reads |------------------------------------------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | | | 3800  
 (100)| | 1 |00:00:19.91 | 13699 | 13695 || 1 | SORT AGGREGATE | | 1 | 1 | 3 | | | 1 |00:00:19.91 | 13699 | 13695 ||* 2 | TABLE ACCESS FULL| EMP0 | 1 | 1998K| 5853K| 3800 (2)| 00:00:46 | 1998K|00:00:10.33 | 13699 | 13695 |------------------------------------------------------------------------------------------------------------------------------  
 Predicate Information (identified by operation id):--------------------------------------------------- 2 - filter("DEPTNO"=TO_NUMBER(SYS_CONTEXT('my_context','deptno'))) <pre class="sql" name="code" snippet_file_name="blog_20140125_12_3496049" code_snippet_id="163969">------------static------------</pre> SQL_ID b82cfwj1skv3d, child number 0-------------------------------------select  
 /*4*/ count(*) from emp0 Plan hash value: 3474440072 ------------------------------------------------------------------------------------------------------------------------------| Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows  
 | A-Time | Buffers | Reads |------------------------------------------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | | | 3800 (100)| | 1 |00:00:17.17 | 13699 | 13695 || 1 | SORT AGGREGATE  
 | | 1 | 1 | 3 | | | 1 |00:00:17.17 | 13699 | 13695 ||* 2 | TABLE ACCESS FULL| EMP0 | 1 | 1998K| 5853K| 3800 (2)| 00:00:46 | 1998K|00:00:08.90 | 13699 | 13695 |------------------------------------------------------------------------------------------------------------------------------  
 Predicate Information (identified by operation id):--------------------------------------------------- 2 - filter("DEPTNO"=TO_NUMBER(SYS_CONTEXT('my_context','deptno')))  
<pre></pre>  
<p></p>  
可以看到<strong>性能差异很小</strong>。<br>  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: