vpd策略函数必须返回varchar2类型谓词字符串,返回null会过滤行,返回空字符串''则无条件放行;函数签名须为function f_policy(p_schema varchar2, p_object varchar2) return varchar2,否则静默失效。
vpd策略函数必须返回varchar2类型谓词字符串
oracle的vpd(virtual private database)机制在执行查询前,会把策略函数返回的字符串拼接到where子句中。如果函数返回null,该行会被过滤掉;返回空字符串'',则相当于无条件放行——这常被误认为“没生效”,实则是逻辑漏洞。函数签名必须严格为:function f_policy(p_schema varchar2, p_object varchar2) return varchar2,返回值不能是boolean或number,否则策略注册失败且不报错,只静默失效。
常见错误现象:SELECT * FROM emp结果为空,但单独查emp表有数据;检查策略函数发现返回了'1=0'或NULL,却没意识到这是策略主动拦截。
- 策略函数内避免直接用
SYS_CONTEXT('USERENV', 'SESSION_USER')做权限判断——应使用SYS_CONTEXT('USERENV', 'CURRENT_SCHEMA')或自定义应用上下文 - 调试时可用
DBMS_RLS.ADD_POLICY的ENABLE => FALSE参数先注册再手动启用,避免策略误触发影响业务 - 函数里慎用DDL或自治事务,VPD执行阶段处于SQL解析期,可能引发ORA-04092等错误
ADD_POLICY时policy_name和function_name不能重名
调用DBMS_RLS.ADD_POLICY注册策略时,policy_name是策略在数据字典中的唯一标识,而function_name指向实际执行过滤的PL/SQL函数。若两者取相同名字(如都叫emp_sec_policy),Oracle不会报错,但在后续DBMS_RLS.ENABLE_POLICY或DROP_POLICY时,系统会混淆对象类型,导致ORA-28103异常:“policy name does not exist”。这不是语法错误,而是元数据解析歧义。
使用场景:多租户系统中,每个租户一张orders分区表,需为每张表绑定独立策略,此时policy_name建议按tenantid_tablename_policy格式命名,function_name统一用f_tenant_filter复用逻辑。
-
object_schema参数必须显式指定,即使当前用户是所有者——省略会导致策略绑定到NULLschema,查询时报ORA-28100 - 对分区表启用VPD,策略默认作用于整个表;如需按分区差异化控制,须在策略函数中解析
DBMS_ROWID.ROWID_OBJECT或结合分区键字段判断 - 策略注册后,可通过
SELECT * FROM DBA_POLICIES WHERE OBJECT_NAME = 'EMP'验证绑定状态
VPD与物化视图、并行查询存在兼容性限制
VPD策略在物化视图刷新(DBMS_MVIEW.REFRESH)过程中不会触发,因为刷新走的是底层直接路径(direct-path insert),绕过了SQL引擎的谓词注入环节。这意味着:如果基表启用了VPD,而物化视图未同步策略,查询MV时将暴露全部数据——典型的数据越权风险。
并行查询(PQ)下,VPD策略函数可能被多个PX进程并发调用,若函数内含包级变量或临时表写入,会出现状态污染。Oracle 12c+虽支持AUTONOMOUS_TRANSACTION隔离,但策略函数本身禁止声明自治事务(ORA-14552)。
- 物化视图必须单独添加同名策略,且函数逻辑需与基表一致;不能依赖“继承”
- 高并发场景下,策略函数应保持无状态,所有上下文信息通过
SYS_CONTEXT获取,避免PKG_AUTH.CURRENT_TENANT类包变量 - 启用
ALTER SESSION SET "_optimizer_push_pred_cost_based"=FALSE可强制谓词下推,缓解VPD导致的执行计划劣化,但仅限诊断阶段使用
测试VPD策略是否生效,别只看SELECT结果
仅靠SELECT * FROM emp观察行数变化,无法确认VPD是否真正介入。因为结果可能受其他因素干扰:比如表上同时存在RAS策略、审计策略,或用户恰好没有SELECT权限而被前置拦截。真实验证要分三层看:
- 查
V$VPD_POLICY确认策略已启用且STATUS = 'ENABLED' - 用
EXPLAIN PLAN FOR SELECT * FROM emp后查PLAN_TABLE,若出现ACCESS_PREDICATES含策略函数返回的谓词(如"DEPT_ID"=SYS_CONTEXT('CTX','DEPT')),说明已注入 - 开启SQL跟踪:
ALTER SESSION SET EVENTS '10730 trace name context forever, level 12',在trace文件中搜索vpd关键字,定位谓词拼接日志
最容易被忽略的是:VPD不改变对象权限模型。即使策略返回'1=1',用户仍需具备基础SELECT权限才能发起查询——权限缺失时看到的是ORA-00942而非空结果,这点常被当成“策略没起作用”。











