Oracle VPD0323.docx
《Oracle VPD0323.docx》由会员分享,可在线阅读,更多相关《Oracle VPD0323.docx(25页珍藏版)》请在冰豆网上搜索。
OracleVPD0323
采用oracle的dbms_rls包实现数据访问控制
在大部份系统中,权限控制主要定义为模块进入权限的控制和数据列访问权限的控制(如:
某某人可以进入某个控制,仓库不充许查看有关部门的字段等等)。
但在某些系统中,权限控制又必须定义到数据行访问权限的控制,此需求一般出现在同一系统,不同的相对独立机构使用的情况。
(如:
集团下属多个子公司,所有子公司使用同一套数据表,但不同子公司的数据相对隔离),绝大多数人会选择在View加上Where子句来进行数据隔离。
此方法编码工作量大、系统适应用户管理体系的弹性空间较小,一旦权限逻辑发生变动,就可能需要修改权限体系,导致所有的View都必须修改。
本文探讨的使用Oracle提供的Policy管理方法来实现数据行的隔离
注意:
这里的policy是在9i上测试,8i的policy是不同9i的,但是原理是一样的.
(1)建立测试数据表(t_policy):
CREATETABLET_POLICY
(
T1 VARCHAR2(10BYTE),
T2 NUMBER(10)
);
insertintot_policyvalues('a',10);
insertintot_policyvalues('b',20);
insertintot_policyvalues('c',30);
commit;
(2)建立测试policy的函数:
CREATEORREPLACEfunctionFn_GetPolicy(P_SchemaInVarchar2,P_ObjectInVarchar2)returnvarchar2is
Resultvarchar2(1000);
begin
Result:
='t2notin(10)';
return(Result);
endFn_GetPolicy;
/
(3)加入policy:
declare
Begin
Dbms_Rls.Add_Policy(
Object_Schema=>'niegc', --数据表(或视图)所在的Schema名称
Object_Name=>'T_Policy',--数据表(或视图)的名称
Policy_Name=>'T_TestPolicy',--POLICY的名称,主要用于将来对Policy的管理
Function_Schema=>'NIEGC', --返回Where子句的函数所在Schema名称
Policy_Function=>'Fn_GetPolicy',--返回Where子句的函数名称
Statement_Types=>'Select,Insert,Update,Delete',--要使用该Policy的DML类型,如'Select,Insert,Update,Delete'
Update_Check=>True,--仅适用于Statement_Type为'Insert,Update',值为'True'或'False'
Enable=>True --是否启用,值为'True'或'False'
);
end;
注:
如果Update_Check设为'True',则用户插入的值不符合Policy_Function返回条件时,该DML执行返回错误信息。
现在就可以工作了:
select*fromt_policy;
看看结果怎样,是不是少了t2=10这项了.
(4)删除policy
declare
begin
dbms_rls.drop_policy('niegc','T_POLICY','T_TESTPOLICY');
end;
(5)设置policy的状态
declare
begin
dbms_rls.enable_policy('niegc','t_policy','t_testpolicy',false);
end;
(6)查看policy可以通过user_policies这个表看到.
2006-10-0223:
55于杭州滨江
9.3.5使用VPD实现应用程序安全策略
(1)
2009-01-2010:
39 刘伟琴 清华大学出版社 我要评论()
∙摘要:
《OracleDatabase11gDBA手册》将介绍Oracle11g最新的特性以及如何将这些特性结合到Oracle数据库管理中。
第9章讲述数据库安全性和审计。
本节说的是使用VPD实现应用程序安全策略。
虚拟专用数据库(VirtualPrivateDatabase,VPD)将服务器实施的细粒度访问控制和安全应用程序上下文结合起来。
支持上下文的函数返回一个谓词,即where子句,该子句自动附加到所有的select语句或其他DML语句。
换句话说,由VPD控制的表、视图、同义词上的select语句将根据where子句返回行的子集,该子句由通过应用程序上下文生效的安全策略函数自动生成。
VPD的主要组成部分是行级别的安全性(RLS),也称为"细粒度的访问控制"(FGAC)。
因为VPD在语句解析期间透明地生成谓词,因此无论用户是否正在运行特别的查询、检索应用程序中的数据或者查看OracleForms中的数据,都可以一致地实施安全策略。
因为OracleServer在解析时将谓词应用于语句,所以应用程序不需要使用特殊的表、视图等来实现该策略。
因此,Oracle可以使用索引、物化视图和并行操作来优化查询,而以其他的方式则不能够进行优化。
因此,相比于使用应用程序或其他方式过滤结果的查询,使用VPD可能会产生较少的系统开销。
从维护的角度来看,安全策略可以在安全函数中定义,使用角色和权限很难创建这种安全函数。
类似地,应用程序服务器提供商(ApplicationServerProvider,ASP)可能只需要建立一个数据库来为相同应用程序的多个客户服务,使用VPD策略来确保一个顾客的雇员只可以查看他们自己的数据。
DBA可以使用少量的VPD策略维护一个较大的数据库,而不是针对每个客户都使用一个单独的数据库。
Oracle10g中的新增内容是列级别的VPD操作。
使用列级别的VPD,DBA可以约束对表中特定列的访问。
查询返回相同数量的行,但如果用户的上下文不允许访问列,则在约束的列中返回NULL值。
VPD策略可以是静态的、上下文相关的或动态的。
静态的或上下文相关的VPD策略是OracleDatabase10g的新增内容,它们可以极大地改进性能,因为它们不需要在每次运行查询时调用策略函数,这是由于在会话中将其缓存以方便以后使用。
在OracleDatabase10g之前,所有的策略都是动态的。
换句话说,每次解析包含目标VPD表的SQL语句时都运行策略函数。
每次登录,静态策略都要评估一次,并且在整个会话期间保持缓存,而不考虑应用程序上下文。
使用上下文相关的策略时,如果应用程序上下文改变,则在语句解析时调用策略函数:
例如,实施"雇员只可以看到他们自己的薪水历史记录,但经理可以看到他们雇员的所有薪水情况"这种业务规则的策略。
如果执行语句的雇员没有改变,就不需要再次调用策略函数,从而减少由于VPD策略实施而产生的系统开销量。
可以使用createcontext命令创建应用程序上下文,并且使用程序包DBMS_RLS管理VPD策略。
可以像其他任何函数一样创建用于返回谓词以实施策略的函数,但这种函数具有两个必需的参数,并且返回一个VARCHAR2。
本章后面将详细介绍这些函数,并且使用在Oracle数据库安装期间提供的示例模式来创建一个VPD示例。
1.应用程序上下文
使用createcontext命令,可以创建应用程序定义的属性的名称,这些属性用于实施安全策略。
此外,还可以定义函数和过程的程序包名称,这些函数和过程用于设置用户会话的安全上下文。
下面是示例:
createcontexthr_securityusingvpd.emp_access;
createorreplacepackageemp_accessas
procedureset_security_parameters;
end;
在该示例中,上下文名称是HR_SECURITY,用于在会话期间为用户建立特征或属性的程序包称为EMP_ACCESS。
在登录触发器中调用过程SET_SECURITY_PARAMETERS。
因为上下文HR_SECURITY只绑定到EMP_ACCESS,因此没有其他的过程可以改变会话属性。
这可以确保在连接到数据库后用户或任何其他进程都不可以改变安全的应用程序上下文。
在用于实现应用程序上下文的典型程序包中,使用内置的上下文USERENV来检索有关用户会话自身的信息。
在表9-13中是USERENV上下文中一些更为常见的参数。
表9-13 常见的USERENV上下文参数
参数
返回值
CURRENT_SCHEMA
会话的默认模式
DB_NAME
在初始参数DB_NAME中指定的数据库名称
HOST
用户连接的主机名称
IP_ADDRESS
用户连接的IP地址
OS_USER
初始化数据库会话的操作系统账户
SESSION_USER
经过验证的数据库用户名
例如,下面对SYS_CONTEXT的调用将检索数据库会话的用户名和IP_ADDRESS:
declare
username varchar2(30);
ip_addr varchar2(30);
begin
username:
=SYS_CONTEXT('USERENV','SESSION_USER');
ip_addr:
=SYS_CONTEXT('USERENV','IP_ADDRESS');
--otherprocessinghere
end;
类似地,可以在SQLselect语句中使用SYS_CONTEXT函数:
SQL>selectSYS_CONTEXT('USERENV','SESSION_USER')usernamefromdual;
USERNAME
-------------------------
KSHELTON
使用USERENV上下文和数据库中授权信息的一些组合,可以使用DBMS_SESSION.SET_CONTEXT,将值赋予所创建的应用程序上下文中的参数:
dbms_session.set_context('HR_SECURITY','SEC_LEVEL','HIGH');
在该示例中,应用程序上下文变量SEC_LEVEL在HR_SECURITY上下文中设置为HIGH。
可以根据大量条件来分配该值,包括根据用户ID来分配安全级别的映射表。
为了确保针对每个会话设置上下文变量,可以使用登录触发器来调用与该上下文关联的过程。
前面提及,在分配的程序包中只可以设置或改变上下文中的变量。
下面是一个示例登录触发器,该触发器调用过程以建立上下文:
createorreplacetriggervpd.set_security_parameters
afterlogonondatabase
begin
vpd.emp_access.set_security_parameters;
end;
在该示例中,过程SET_SECURITY_PARAMETERS将需要调用DBMS_SESSION.SET_CONTEXT。
在OracleEnterpriseManager中,可以使用PolicyManager来建立上下文和策略组,如图9-8所示。
(点击查看大图)图9-8 OraclePolicyManager
9.3.5使用VPD实现应用程序安全策略
(2)
2.安全策略实现
基础结构到位之后,就可以建立安全环境,下一步就是定义用于生成谓词的函数,这些谓词将附加到受保护表的每个select语句或DML命令。
用于实现谓词生成的函数有2个参数:
受保护对象的拥有者、拥有者模式中对象的名称。
一个函数只可以处理一种操作类型的谓词生成,例如select,或者可以适用于所有的DML命令,这取决于该函数如何关联受保护的表。
下面的示例显示了包含两个函数的程序包主体:
一个函数将用于控制select语句中的访问,另一个函数将用于任何其他的DML语句:
createorreplacepackageget_predicatesis
functionemp_select_restrict(ownervarchar2,object_namevarchar2)
returnvarchar2;
functionemp_dml_restrict(ownervarchar2,object_namevarchar2)
returnvarchar2;
endget_predicates;
/
createorreplacepackagebodyget_predicatesis
functionemp_select_restrict(ownervarchar2,object_namevarchar2)
returnvarchar2is
ret_predicate varchar2(1000); --partofWHEREclause
begin
--onlyallowcertainemployeestoseerowsinthetable
--...checkcontextvariablesandbuildpredicate
returnret_predicate;
endemp_select_restrict;
functionemp_dml_restrict(ownervarchar2,object_namevarchar2)
returnvarchar2is
ret_predicate varchar2(1000); --partofWHEREclause
begin
--onlyallowcertainemployeestomakechangestothetable
--...checkcontextvariablesandbuildpredicate
returnret_predicate;
endemp_dml_restrict;
end;--packagebody
/
每个函数返回一个包含表达式的字符串,该表达式被添加到select语句或DML命令的where子句。
用户或应用程序永远不会看到这个WHERE子句的值,它在解析时自动添加到该命令。
开发人员必须确保这些函数总是返回有效的表达式。
否则,任何对受保护表的访问总会失败,如同下面的示例所示:
SQL>select*fromhr.employees;
select*fromhr.employees
*
ERRORatline1:
ORA-28113:
policypredicatehaserror
错误消息不会表明谓词是什么,并且所有的用户都无法访问表,直到修正谓词函数。
本章后面将介绍关于如何调试谓词函数的技巧。
9.3.5使用VPD实现应用程序安全策略(3)
3.使用DBMS_RLS
内置的程序包DBMS_RLS包含大量子程序,DBA使用这些子程序维护与表、视图和同义词关联的安全策略。
表9-14列出了程序包DBMS_RLS中的子程序。
任何需要创建和管理策略的用户都必须被授予程序包SYS.DBMS_RLS上的EXECUTE权限。
表9-14 DBMS_RLS程序包的子程序
子程序
说明
ADD_POLICY
将细粒度的访问控制策略添加到对象
DROP_POLICY
删除对象中的FGAC策略
REFRESH_POLICY
重新解析与策略关联的、缓存的所有语句
ENABLE_POLICY
启用或禁用FGAC策略
CREATE_POLICY_GROUP
创建策略组
ADD_GROUPED_POLICY
将策略添加到策略组
ADD_POLICY_CONTEXT
添加当前应用程序的上下文
DELETE_POLICY_GROUP
删除策略组
DROP_GROUPED_POLICY
从策略组中删除一个策略
DROP_POLICY_CONTEXT
删除活动应用程序的上下文
ENABLE_GROUPED_POLICY
启用或禁用组策略
DISABLE_GROUPED_POLICY
禁用组策略
REFRESH_GROUPED_POLICY
重新解析与策略组关联的、缓存的所有语句
本章将介绍最常用的子程序ADD_POLICY和DROP_POLICY。
ADD_POLICY的语法如下:
DBMS_RLS.ADD_POLICY
(
object_schema INvarchar2null,
object_name INvarchar2,
policy_name INvarchar2,
function_schema INvarchar2null,
policy_function INvarchar2,
statement_types INvarchar2null,
update_check INbooleanfalse,
enable INbooleantrue,
static_policy INbooleanfalse,
policy_type INbinary_integernull,
long_predicate INinBooleanfalse,
sec_relevant_cols INvarchar2,
sec_relevant_cols_opt INbinary_integernull
);
注意,其中一些参数具有BOOLEAN默认值,并且较少使用的参数都在参数列表的末端。
对于绝大多数情况来说,这就使对DBMS_RLS.ADD_POLICY的特定调用的语法更易于编写和理解。
表9-15提供了每个参数的说明和用法。
表9-15 DBMS_RLS.ADD_POLICY的参数
参数
说明
object_schema
包含由策略保护的表、视图或同义词的模式。
如果该值是NULL,则使用调用过程的用户的模式
object_name
由策略保护的表、视图或同义词的名称
policy_name
添加到该对象的策略的名称。
对于受保护的每个对象,该策略名必须唯一
function_schema
拥有策略函数的模式;如果该值为NULL,则使用调用过程的用户的模式
policy_function
函数名称,该函数为针对object_name的策略生成谓词。
如果函数是程序包的一部分,则在此处必须也指定程序包名,用于限定策略函数名
statement_types
应用策略的语句类型。
允许的值(以逗号分隔)可以是SELECT、INSERT、UPDATE、DELETE和INDEX的任意组合。
默认情况下,除了INDEX之外的所有类型都适用
update_check
对于INSERT或UPDATE类型,该参数是可选项,它默认为FALSE。
如果该参数为TRUE,则在检查SELECT或DELETE操作时,则对INSERT或UPDATE语句也要检查该策略
enable
该参数默认为TRUE,表明添加该策略时是否启用它
Static_policy
如果该参数为TRUE,该策略为任何访问该对象的人产生相同的谓词字符串,除了SYS用户或具有EXEMPTACCESSPOLICY权限的任何用户。
该参数的默认值为FALSE
policy_type
如果该值不是NULL,则覆盖static_policy。
可允许的值是STATIC、SHARED_STATIC、CONTEXT_SENSITIVE、SHARED_CONTEXT_SENSITIVE和DYNAMIC
Long_predicate
该参数默认为FALSE。
如果它为TRUE,谓词字符串最多可为32K字节长。
否则,限制为4000字节
sec_relevant_cols
实施列级别的VPD,这是Oracle10g的新增内容。
只应用于表和视图。
在列表中指定受保护的列,使用逗号或空格作为分隔符。
该策略只应用于指定的敏感列位于查询或DML语句中时。
默认情况下,所有的列都是受保护的
sec_relevant_cols_opt
允许在列级别VPD过滤查询中的行仍然出现在结果集中,敏感列返回NULL值。
该参数的默认值为NULL;如果不是默认值,则必须指定DBMS_RLS.ALL_ROWS,用于显示敏感列为NULL的所有列
如果不介意用户是否会看到行的部分内容,其实只是看不到包含机密信息的列,例如SocialSecurityNumber(社会保障号)或薪水情况,则使用参数sec_relevant_cols非常便利。
在本章后面的示例中,将根据定义的第一个安全策略对公司大多数雇员过滤敏感数据。
在下面的示例中,将名为EMP_SELECT_RESTRICT的策略应用于表HR.EMPLOYEES。
模式VPD拥有策略函数get_predicates.emp_select_restrict。
该策略显式地应用于表上的SELECT语句。
然而,将UPDATE_CHECK设置为TRUE时,在更新行或将行插入到表中时,也会检查update或delete命令:
dbms_rls.add_policy(
object_schema=> 'HR',
object_name=> 'EMPLOYEES',
policy_name=> 'EMP_SELECT_RESTRICT',
function_schema=> 'VPD',
policy_function=> 'get_predicates.emp_select_restrict',
statement_types=> 'SELECT',
update_check=> TRUE,
enable=> TRUE
);
因为没有设置static_policy,它默认为FALSE,这意味着该策略是动态的,并且在每次解析select语句时检查该策略。
这是在OracleDatabase10g之前唯一可用的行为。
使用子程序ENABLE_POLICY是临时禁用策略的一种简单方法,并且不需要在以后将策略重新绑定到表:
dbms_rls.enable_policy(
object_schema=> 'HR',
object_name=> 'EMPLOYEES',
policy_name=> 'EMP_SELECT_RESTRICT',
enable=>