Oracle8i以后的版本都提供了VPD(virtual private database 虚拟专用数据库)这样一个强大的功能来实现呼声日益增高的系统安全性要求。
通过设置基于VPD的细粒度访问策略,我们可以只通过DBA的工作(不需要修改应用,也就是应用透明化)就可以实现用户只能访问自己有权限访问的数据,当然如果需要更加复杂的权限控制开发人员的参与还是必不可少的。
下面用一个简单的例子来实现这样的功能,在EMP表中的用户登录数据库以后只能查询和更新自己所属部门的其它员工资料,不是本部门的不会显示也不允许更新。
1. 我们需要用到3个用户,一个是拥有EMP表的SCOTT用户,一个是用于设置VPD策略的KAMUS用户,另外一个是在EMP表中有记录的SMITH用户。
SCOTT用户可以利用$ORACLE_HOME/rdbms/admin/scott.sql创建。
@?/rdbms/admin/scott.sql
KAMUS用户需要能够执行DBMS_RLS包的权限。
grant execute on dbms_rls to kamus;
SMITH用户需要能够读取并更新EMP表的权限。
grant select on scott.emp to smith;
2. 首先用KAMUS用户创建策略权限表。为方便起见我们直接通过EMP表创建,本策略表中包含了员工姓名和所属部门编号。为了更加完善策略函数,我们创建完策略表后在表中新增一条记录,让SMITH用户同时属于20和10这两个部门。
SQL> create table access_policy as select ename,deptno from scott.emp;
Table created
SQL> select * from access_policy;
ENAME DEPTNO
———- ——
SMITH 20
ALLEN 30
WARD 30
JONES 20
MARTIN 30
BLAKE 30
CLARK 10
KING 10
TURNER 30
JAMES 30
FORD 20
MILLER 10
12 rows selected
SQL> insert into access_policy values(‘SMITH’,10);
1 row inserted
SQL> commit;
Commit complete
3. KAMUS用户创建VPD策略需要的函数。
(
p_schema in varchar2,
p_table in varchar2
)
return varchar2
as
l_retstr varchar2(2000);
begin
if (p_schema = user) then
l_retstr := null;
else
for user_rec in
(
select deptno
from access_policy
where ename = USER
) loop
l_retstr := l_retstr||’,’||user_rec.deptno;
end loop;
l_retstr := ltrim(l_retstr,’,’);
if (l_retstr is null) then
l_retstr := ‘1=2’;
else
l_retstr := ‘DEPTNO IN (‘||l_retstr||’)’;
end if;
end if;
return l_retstr;
end;
该函数实现以下功能:
如果使用SCOTT用户登录,因为表是属于该用户的,所以不加任何限制。
如果使用其它用户登录(SYS用户不受此限制),那么根据EMP表中该用户的所属部门决定哪些记录允许该用户操作,本例中10和20这两个部门的员工SMITH用户将都能看见。
如果登录的用户不在EMP表中,那么该用户查看不到任何数据,比如KAMUS用户。
注意:
VPD策略函数必须包含两个参数,本例中是p_schema和p_table,即使这两个参数在函数中没有用到,也必须包含。否则在后面检索EMP表数据的时候将会报:
PLS-00306: 调用 ‘GET_USER_DEPT_ID’ 时参数个数或类型错误。
我们用SMITH用户登录数据库来测试一下这个函数的返回值。
KAMUS.GET_USER_DEPT_ID(‘SCOTT’
——————————————————————————–
DEPTNO IN (20,10)
也就是说基于VPD的细粒度访问策略实际上就是在用户提交一个SQL以后会将策略函数返回值添加到where语句后面,通过这种方式来限制用户对于表中数据的访问。
4. 用KAMUS用户创建VPD策略。
begin
dbms_rls.add_policy (
object_schema => ‘SCOTT’,
object_name => ‘EMP’,
policy_name => ‘EMP_SEL_POLICY’,
function_schema => ‘KAMUS’,
policy_function => ‘GET_USER_DEPT_ID’,
statement_types => ‘SELECT’
);
end;
/
这是用于select的策略。
begin
dbms_rls.add_policy (
object_schema => ‘SCOTT’,
object_name => ‘EMP’,
policy_name => ‘EMP_IUD_POLICY’,
function_schema => ‘KAMUS’,
policy_function => ‘GET_USER_DEPT_ID’,
statement_types => ‘INSERT, UPDATE, DELETE’,
update_check => TRUE
);
end;
/
这是用于DML的策略。
5. 至此为止我们的VPD方案就已经设置完毕了。下面我们测试一下。
SQL> conn scott/tiger
已连接。
–SCOTT用户可以选择出全部的12条记录
SQL> select count(*) from emp;
COUNT(*)
———-
12
SQL> conn smith/smith
已连接。
–SMITH用户只能选择出属于10,20部门的6条记录
SQL> select count(*) from scott.emp;
COUNT(*)
———-
6
–更新也只能更新6行记录
SQL> update scott.emp set sal=sal+100;
已更新6行。
–如果尝试插入一个其它部门的员工将会报错
SQL> insert into scott.emp(empno,ename,deptno) values(9999,’VPD’,30);
insert into scott.emp(empno,ename,deptno) values(9999,’VPD’,30)
*
第 1 行出现错误:
ORA-28115: 策略违反检验选项
–即使指定了要更新30部门的数据也是一条都无法更新
SQL> update scott.emp set sal=sal+100 where deptno=30;
已更新0行。
–同样删除也只能删除6行数据
SQL> delete scott.emp;
已删除6行。
结论:
通过基于VPD的细粒度访问策略可以很简单地在数据库这个层面上完成对于应用数据的安全性保护,而如果通过SYS_CONTEXT以及数据库登录触发器来编写更加复杂的VPD策略函数的话,就能实现非常强大的数据安全性功能。
后续:
Oracle数据库安全领域有很多我还没有接触到的东西需要学习,下面一篇文章我将会介绍同样是基于VPD的更深一步的安全策略解决方案 - Label Security,敬请期待。
以后用户会越来越关注安全问题。
Kamus有没有留意到Oracle Database Vault 这个新特性? 它能防止 DBA 查看应用程序数据,解决了必须保护涉及合作伙伴、员工和顾客的敏感业务信息或隐私数据的客户最为担心的问题。
我没有机会用,希望什么时候能看到Kamus的测试结果。
VPD能控制普通用户,但不能控制DBA
by the way,请教一个问题:
听说你们consulting团队有人给客户实施过logical standby,想咨询现网使用的情况,是否稳定等等。方便的话能和我邮件联系吗?谢谢。
to dido
Oracle Database Vault的测试正在计划ing,因为目前只有linux和solaris版本发布,所以需要先安装一个for linux的db在自己的机器上。
Label Security昨天已经测试完毕,正在整理文章。
是有同事实施过DG,但是据说仍然是physical standby,我以前的客户自己实施过logical standby,目前一直在使用,有时候出现主备数据不一致的情况需要手工进行错误处理,其它的倒没听到什么不好。