VPD介绍
Oracle VPD(Virtual Private Database,虚拟私有数据库)是一个Oracle数据库的安全特性,它允许数据库管理员定义和实施细粒度的数据访问控制策略。通过使用VPD,管理员可以定义行级别和列级别的安全策略,以控制用户对数据库中数据的访问。
Oracle VPD可以为不同的用户提供不同的数据视图,以控制对敏感数据的访问,具有如下优势:
Ø 数据安全性:VPD可以控制不同用户对数据库中数据的访问权限,从而保证数据的安全性。只有被授权的用户可以访问数据,从而减少了因非授权用户访问敏感数据而导致的数据泄露或滥用的风险。
Ø 简化开发:VPD可以让开发人员在不改变应用程序代码的情况下实现数据权限控制。这样可以节省开发时间和开发成本,并且更加灵活地调整数据权限。
Ø 提高性能:VPD在数据库查询中应用了一些优化技术,例如谓词下推,可以在保证数据安全性的前提下提高查询性能。
Ø 简化管理:VPD可以为管理员提供一种集中管理和控制数据库访问权限的方式。管理员可以通过配置VPD规则来实现数据权限控制,而无需为每个用户单独配置访问权限。
Ø 降低风险:VPD可以控制用户对敏感数据的访问权限,从而降低了数据泄露和滥用的风险。此外,VPD还可以记录数据库访问日志,帮助管理员跟踪数据库访问情况并发现潜在的安全威胁。
权限控制简介
权限控制主要包括两方面:功能控制和数据控制。APEX可以很方便的实现各种粒度的功能控制,从功能模块、菜单、页面到单个输入框、按钮等都可以通过配置的方式很方便的实现;本文将重点讲述在APEX应用中如何结合Oracle数据库的VPD特性方便灵活地实现数据层面的权限控制。
VPD策略配置
实例策略描述
作为实例,我们将实现一个这样的策略:
【登录用户能查看他自己以及下属(包括下属的下属…)所有销售代表的订单数据,不能查看同一级其他员工的数据或上级的其它数据】
这里涉及到两个表:
Ø 员工表:定义了员工登录应用的信息,以及员工的层级关系
OEHR_EMPLOYEES EMPLOYEE_ID – 员工ID EMAIL – 作为APEX应用的登录名 MANAGER_ID – 员工的上级经理 … … |
Ø 订单表:定义了与员工相关联的订单
OEHR_ORDERS ORDER_ID – 订单号 SALES_REP_ID – 销售代表,对应员工表中的EMPLOYEE_ID … … |
要实现这样一个策略,我们的目标其实就是 从OEHR_ORDERS表中找到所有属于自己以及下属(包括下属的下属…)的所有订单,也就类似:
Select * from OEHR_ORDERS where SALES_REP_ID IN (‘自己’, ‘下属’, ‘下属的下属…’);
策略实现
策略以Function的方式实现,灵活方便。请查看以下样例及注解。这只是一个样例实现,实际场景中可以根据具体情况定义逻辑。
create or replace function "F_POLICY_ORDERS_BY_MANAGER" (
schema in VARCHAR2,
tab in VARCHAR2
) return VARCHAR2
is
v_login varchar2(256);
v_conn_user varchar2(256);
predicate varchar2(400);
begin
-- 从APEX会话中获取当前登录用户.
v_login := V('APP_USER');
-- 从数据库连接会话中获取当前数据库用户
v_conn_user := SYS_CONTEXT('USERENV','SESSION_USER');
if v_login IN ('HYSUN') OR v_conn_user IN ('SYS') then
-- 允许APEX工作区管理员(这里是HYSUN)和SYS DBA能够查看所有数据
predicate := '1=1';
else
-- 除了APEX工作区管理员和SYS DBA,限制其它所有人只能查看自己及下属的订单数据
predicate := 'SALES_REP_ID IN (
SELECT employee_id
FROM OEHR_EMPLOYEES
START WITH EMAIL=''' || v_login || '''
CONNECT BY PRIOR employee_id = manager_id
)';
end if;
return predicate;
exception
when no_data_found then
null;
end;
/
策略绑定
将策略绑定到具体的数据库对象上去。数据库对象可以是表,也可以是视图,同义词。
执行策略绑定需要有DBMS_RLS包的执行权限,如果报没权限错误,需要先授予权限:
GRANT EXECUTE ON DBMS_RLS TO <db_user>;
BEGIN
DBMS_RLS.ADD_POLICY(
object_schema => 'poc',
object_name => 'OEHR_ORDERS',
policy_name => 'query_orders_by_manager',
policy_function => 'F_POLICY_ORDERS_BY_MANAGER',
statement_types => 'SELECT');
END;
/
以上”statement_types”指定了在查询语句上应用策略,同样,我们也可以指定为”update”, “delete”等情形。
简单演示
订单查询页的报表SQL句没加任何的where条件,如下:
然后用公司最高领导人SKING登录,能看到所有订单(70条):
再用一个经理 KPARTNER登录,他只能看到属于他及下属的订单(38条):
说明我们定义的策略根据登录用户动态的应用到了数据层面,从而有效控制了数据的安全访问。
总结
Oracle VPD能细粒度的控制数据的安全访问,能够达到行级别。其实通过简单的增加指定列的策略参数,还能达到列级别的控制(这里没作演示,可以查看具体资料)。
通过 VPD安全控制的对象,不管用什么渠道访问(sqlplus, sql developer, apex, 其它sql客户端…),得到的结果都是一样,从而避免了 “应用层面作了数据安全控制,但如果绕过应用层面用其它客户端访问数据,就没有数据安全控制“ 的情况,有效增加了数据的安全性。
更多参考资料
https://docs.oracle.com/en/database/oracle/oracle-database/19/dbseg/using-oracle-vpd-to-control-data-access.html