Oracle VPD
VPD = Virtual Private Database。同义词有RLS : Row Level Security, FGAC: Fine Grained Access Control。
用于行级访问控制。假设有需求,只有用户'SCOTT'能访问emp表所有记录,其他人只能访问manager以下员工的记录。
CREATE FUNCTION emp_policy(schema_in IN VARCHAR2,object_in IN VARCHAR2)
RETURN VARCHAR2
ISl_return_value VARCHAR2(32767);
BEGINIF SYS_CONTEXT('USERENV', 'SESSION_USER') = 'SCOTT' THENl_return_value := '1=1';ELSEl_return_value := 'JOB NOT IN (''PRESIDENT'',''MANAGER'')';END IF; RETURN l_return_value;
END;BEGINDBMS_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部分。
我们测试一下:
[oracle@odilab ~]$ sqlplus scott/a123456SQL*Plus: Release 11.2.0.1.0 Production on Sun Jan 19 22:52:20 2014Copyright (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) 107369 SMITH CLERK 7902 17-DEC-80 800 (null) 207499 ALLEN SALESMAN 7698 20-FEB-81 1600 300 307521 WARD SALESMAN 7698 22-FEB-81 1250 500 307566 JONES MANAGER 7839 02-APR-81 2975 (null) 207654 MARTIN SALESMAN 7698 28-SEP-81 1250 1400 307698 BLAKE MANAGER 7839 01-MAY-81 2850 (null) 307782 CLARK MANAGER 7839 09-JUN-81 2450 (null) 107788 SCOTT ANALYST 7566 19-APR-87 3000 (null) 207839 KING PRESIDENT (null) 17-NOV-81 5000 (null) 107844 TURNER SALESMAN 7698 08-SEP-81 1500 0 307876 ADAMS CLERK 7788 23-MAY-87 1100 (null) 207900 JAMES CLERK 7698 03-DEC-81 950 (null) 307902 FORD ANALYST 7566 03-DEC-81 3000 (null) 207934 MILLER CLERK 7782 23-JAN-82 1300 (null) 1015 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) 207499 ALLEN SALESMAN 7698 20-FEB-81 1600 300 307521 WARD SALESMAN 7698 22-FEB-81 1250 500 307654 MARTIN SALESMAN 7698 28-SEP-81 1250 1400 307788 SCOTT ANALYST 7566 19-APR-87 3000 (null) 207844 TURNER SALESMAN 7698 08-SEP-81 1500 0 307876 ADAMS CLERK 7788 23-MAY-87 1100 (null) 207900 JAMES CLERK 7698 03-DEC-81 950 (null) 307902 FORD ANALYST 7566 03-DEC-81 3000 (null) 207934 MILLER CLERK 7782 23-JAN-82 1300 (null) 1010 rows selected.
我们也可以在session中声明自己的context,并给context赋值,最终由context中的值决定l_return_value。如下所示:
CREATE OR REPLACE CONTEXT MY_CONTEXT USING MY_CONTEXT_PKG;
CREATE OR REPLACE PACKAGE my_context_pkg ISPROCEDURE SET_MAX_DEPT;
END MY_CONTEXT_PKG;CREATE OR REPLACE PACKAGE BODY my_context_pkg ISPROCEDURE set_max_deptASl_max_deptno NUMBER;BEGINCASE 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
BEGINscott.my_context_pkg.set_max_dept;
END;CREATE FUNCTION DEPT_POLICY(SCHEMA_IN IN VARCHAR2,OBJECT_IN IN VARCHAR2)
RETURN VARCHAR2
ISl_return_value VARCHAR2 (32767);BEGINCASE 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
select object_owner, object_name, policy_name, pf_owner, function, enable, static_policy, policy_type
from all_policies;
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被调用次数
create or replace function dept_policy(schema_in in varchar2,object_in in varchar2)
RETURN VARCHAR2
IS
begindbms_application_info.set_client_info(userenv('client_info')+1); RETURN '1=1';
END;exec dbms_rls.drop_policy('SCOTT','DEPT','DEPT_POLICY');
BEGINDBMS_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 DYNAMICexec 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配置:
CREATE OR REPLACE FUNCTION EMP_POLICY(P_SCHEMA IN VARCHAR2, P_OBJECT IN VARCHAR2)
RETURN VARCHAR2
IS
BEGINdbms_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
----------
CLARKElapsed: 00:00:00.00
$clark@ORCL> connect scott/xxx
Connected.
$scott@ORCL> select ename from scott.emp;ENAME
----------
SCOTTElapsed: 00:00:00.01
SQL_ID 5nwx8yqg94xdy, child number 1
-------------------------------------
select ename from scott.empPlan 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(总裁们所在部门)的工资信息不希望被查询到。
CREATE OR REPLACE FUNCTION EMP_POLICY(P_SCHEMA IN VARCHAR2, P_OBJECT IN VARCHAR2)
RETURN VARCHAR2
IS
BEGINDBMS_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 80020 JONES 297520 SCOTT 300020 ADAMS 110020 FORD 3000Elapsed: 00:00:00.00
$scott@ORCL> select deptno, ename from emp;DEPTNO ENAME
---------- ----------10 HUIYE20 SMITH30 ALLEN30 WARD20 JONES30 MARTIN30 BLAKE10 CLARK20 SCOTT10 KING30 TURNER20 ADAMS30 JAMES20 FORD10 MILLER15 rows selected.Elapsed: 00:00:00.01
可以看到,只要用户试图查找deptno=10的员工的薪水,那么deptno=10的行就不显示。也就是说,用户查询sal时,policy function给出的predicate就会被加到sql中。
Data Masking
CREATE OR REPLACE FUNCTION EMP_POLICY(P_SCHEMA IN VARCHAR2, P_OBJECT IN VARCHAR2)
RETURN VARCHAR2
IS
BEGINDBMS_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 999910 MILLER 130010 KING 500010 CLARK 245020 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如下:
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_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')))
------------dynamic------------
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')))
------------static------------
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')))
可以看到性能差异很小。
Oracle VPD相关推荐
- oracle vpd策略,oracle vpd 策略查询
Oracle VPD策略示例 - abce - 博客园 2015年12月14日 Oracle VPD策略示例 1.未创建前使用oe用户登录查询: + View Code + View Code 2.创 ...
- ORACLE VPD方案
ORACLE VPD方案DROP USER VPD CASCADE; DROP ROLE R_VPD; CREATE USER VPD IDENTIFIED BY VPD; CREATE ROLE R ...
- 【VPD】使用Oracle VPD(Virtual Private Database)限制用户获取数据的范围
VPD全称Virtual Private Database,这个技术提供了对数据库信息的细粒度访问控制.关于VPD的更多描述性信息可通过Oracle官方文档获得:http://download.ora ...
- [精]Oracle VPD详解(虚拟专用数据库)
所谓虚拟专用数据库(VPD)指的是,通过在数据库里进行配置,从而让不同的用户只能查看某 个表里的部分数据.VPD分为以下两个级别. 行级别:在该级别下,可以控制某些用户只能查看到某些数据行.比如,对于 ...
- 利用Oracle VPD实现行级安全保护(二)
通过VPD策略的设置,David只能够查看部门60和80的记录. SQL> conn david Enter password: Connected. SQL> select emplo ...
- oracle访问控制策略查看,ORACLE 安全访问策略VPD与ORA-28132
今天下午,开发同事反馈,某地市的医保oracle数据库执行存储过程报错,报错信息是ORA-28132: ERROR IS:ORA-28132: MERGE INTO 语法不支持安全策略 相关的sql语 ...
- 利用Oracle虚拟私有数据库进行整合
Oracle虚拟私有数据库(Virtual Private Database,下文简称VPD)是Oracle数据库产品中提供的一个安全功能,它能够保证Oracle数据库的多租户特性,与此同时,可以帮助 ...
- mysql实现vpd_Oracle Virtual Private Database(VPD) 初体验
注:本文为原创,作为学习交流使用,转载请标明作者及出处,作者保留追究法律责任的权力. Lumen Su 前几周初略学习了Oracle的VPD技,做了几个试验,也在EBS系统上测试了一下.总结如下,有些 ...
- oracle vdp 实现数据权限
在应用系统开发领域,功能权限和数据权限两层权限体系占到了安全功能性需求的大半.除了在应用程序层面进行处理之外,我们其实还可以从数据库层面实现数据权限访问的. Oracle VPD(Virtual Pr ...
最新文章
- ci框架 mysql_CodeIgniter (CI)框架中的数据库查询汇总
- 关于工大瑞普Dynamips模拟器
- python filter()函数(与map()、reduce()函数用法类似,根据给定函数判断列表元素是True还是False,返回剔除元素后的元素列表)
- 华中科技大学主校区论文被《SCI》收录的研究
- bilibili弹幕转ass
- 201409-1-相邻数对
- 宝软网java软件下载_手机游戏怎么下载
- 计算机应用基础数制试题及答案,计算机应用基础试题及答案1
- 总结:86版五笔输入法
- vtk学习教程(一)
- 音创a55怎么安装系统_怎么安装系统|教你怎样安装系统教程
- html5怎么播放3gp,写了个html5播放视频的video控件,只支持mp4和3gp(android和ios默认支持的格式就写了这个)...
- 入门安全测试需要知道什么?需要掌握哪些知识?
- 微服务之服务监控篇 ActuatorAdmin
- 【12c】扩展数据类型(Extended Data Types)-- MAX_STRING_SIZE
- LSA/LSI算法原理和实践
- 工程伦理--4.1 解决伦理困境的一般步骤
- android 微信分身开发,【技巧】2021安卓手机微信分身方法
- 学校信息计算机教案百度文库,人教版信息技术教案 八年级下册_百度文库(45页)-原创力文档...
- 为什么要早点进入软件测试行业?现在加入晚了吗?
热门文章
- 响应服务器554,服务器554
- python自动发邮件报554错误_python3 使用smtplib发送邮件错误554
- 更安静的听音乐,摆脱户外噪音干扰,哈氪拾光Pro主动降噪耳机体验
- python控制modem的at指令_MODEM AT指令集
- android界面设计的解剖,ps cc 2017启动画面的制作解剖
- python学习 python实现证件照剪裁、缩放、修改底色
- 宋家瑜:做中国的威睿而不是VMware中国
- sql 获取日期时分秒_Sql 中获取年月日时分秒的函数
- 【复习】系统安全知识点归纳总结
- Docker存储卷简述和测试