Part01-基础概念与理论知识
1.1 虚拟私有数据库的概念
虚拟私有数据库(Virtual Private Database,VPD)是Oracle数据库的一项安全特性,它通过在SQL语句执行时自动添加行级过滤条件,实现对表中数据的细粒度访问控制。
学习交流加群风哥QQ113257174
1.2 VPD的工作原理
VPD的工作原理是通过创建安全策略,当用户访问表时,Oracle会自动在SQL语句中添加WHERE子句,过滤掉用户无权访问的数据行。这种过滤对用户是透明的,用户无法绕过。
风哥提示:VPD可以基于用户身份、角色、应用上下文等多种因素来控制数据访问
1.3 VPD的优势与应用场景
- 细粒度访问控制:可以控制到行级别的数据访问
- 透明性:对应用程序透明,无需修改应用代码
- 集中管理:安全策略集中管理,便于维护
- 审计追踪:可以跟踪谁访问了什么数据
更多视频教程www.fgedu.net.cn
Part02-生产环境规划与建议
2.1 VPD设计原则
- 最小权限原则:只授予用户必要的数据访问权限
- 明确的安全策略:安全策略应该清晰明确,易于理解
- 性能考虑:VPD会增加SQL执行开销,需要合理设计
- 可维护性:安全策略应该易于维护和更新
2.2 VPD性能考虑
在生产环境中,VPD可能会对性能产生一定影响,建议:
- 合理设计安全策略,避免复杂的过滤条件
- 为VPD过滤条件创建适当的索引
- 定期监控VPD对性能的影响
- 考虑使用Oracle的分区功能,减少VPD的开销
学习交流加群风哥微信: itpux-com
2.3 VPD安全最佳实践
- 使用应用上下文存储用户信息,避免硬编码
- 定期审查安全策略,确保权限控制合理
- 使用绑定变量,避免SQL注入
- 记录VPD策略的变更,便于审计
更多学习教程公众号风哥教程itpux_com
Part03-生产环境项目实施方案
风哥教程参考Oracle官方文档Security部分,我们将实施以下步骤:
- 创建应用上下文
- 创建安全策略函数
- 创建VPD策略
- 测试VPD效果
- 监控VPD性能
from oracle:www.itpux.com
Part04-生产案例与实战讲解
4.1 创建测试表
命令:CREATE TABLE fgedu.employees (
employee_id NUMBER(6),
first_name VARCHAR2(20),
last_name VARCHAR2(25),
email VARCHAR2(25),
department_id NUMBER(4),
manager_id NUMBER(6),
salary NUMBER(8,2)
);INSERT INTO fgedu.employees VALUES (100, ‘Steven’, ‘King’, ‘steven.king@fgedu.net.cn’, 90, NULL, 24000);INSERT INTO fgedu.employees VALUES (101, ‘Neena’, ‘Kochhar’, ‘neena.kochhar@fgedu.net.cn’, 90, 100, 17000);INSERT INTO fgedu.employees VALUES (102, ‘Lex’, ‘De Haan’, ‘lex.dehaan@fgedu.net.cn’, 90, 100, 17000);INSERT INTO fgedu.employees VALUES (200, ‘Jennifer’, ‘Whalen’, ‘jennifer.whalen@fgedu.net.cn’, 10, 101, 4400);INSERT INTO fgedu.employees VALUES (201, ‘Michael’, ‘Hartstein’, ‘michael.hartstein@fgedu.net.cn’, 20, 100, 13000);COMMIT;执行:输出日志:Table created.1 row created.1 row created.1 row created.1 row created.1 row created.Commit complete.
employee_id NUMBER(6),
first_name VARCHAR2(20),
last_name VARCHAR2(25),
email VARCHAR2(25),
department_id NUMBER(4),
manager_id NUMBER(6),
salary NUMBER(8,2)
);INSERT INTO fgedu.employees VALUES (100, ‘Steven’, ‘King’, ‘steven.king@fgedu.net.cn’, 90, NULL, 24000);INSERT INTO fgedu.employees VALUES (101, ‘Neena’, ‘Kochhar’, ‘neena.kochhar@fgedu.net.cn’, 90, 100, 17000);INSERT INTO fgedu.employees VALUES (102, ‘Lex’, ‘De Haan’, ‘lex.dehaan@fgedu.net.cn’, 90, 100, 17000);INSERT INTO fgedu.employees VALUES (200, ‘Jennifer’, ‘Whalen’, ‘jennifer.whalen@fgedu.net.cn’, 10, 101, 4400);INSERT INTO fgedu.employees VALUES (201, ‘Michael’, ‘Hartstein’, ‘michael.hartstein@fgedu.net.cn’, 20, 100, 13000);COMMIT;执行:输出日志:Table created.1 row created.1 row created.1 row created.1 row created.1 row created.Commit complete.
4.2 创建应用上下文
命令:CREATE CONTEXT fgedu_ctx USING fgedu_ctx_pkg;执行:输出日志:Context created.
4.3 创建上下文包
命令:CREATE OR REPLACE PACKAGE fgedu_ctx_pkg AS
PROCEDURE set_context(p_user VARCHAR2, p_dept_id NUMBER);END fgedu_ctx_pkg;/CREATE OR REPLACE PACKAGE BODY fgedu_ctx_pkg AS
PROCEDURE set_context(p_user VARCHAR2, p_dept_id NUMBER) IS
BEGIN
DBMS_SESSION.SET_CONTEXT(‘fgedu_ctx’, ‘user_id’, p_user);DBMS_SESSION.SET_CONTEXT(‘fgedu_ctx’, ‘dept_id’, p_dept_id);END set_context;END fgedu_ctx_pkg;/执行:输出日志:Package created.Package body created.
PROCEDURE set_context(p_user VARCHAR2, p_dept_id NUMBER);END fgedu_ctx_pkg;/CREATE OR REPLACE PACKAGE BODY fgedu_ctx_pkg AS
PROCEDURE set_context(p_user VARCHAR2, p_dept_id NUMBER) IS
BEGIN
DBMS_SESSION.SET_CONTEXT(‘fgedu_ctx’, ‘user_id’, p_user);DBMS_SESSION.SET_CONTEXT(‘fgedu_ctx’, ‘dept_id’, p_dept_id);END set_context;END fgedu_ctx_pkg;/执行:输出日志:Package created.Package body created.
4.4 创建安全策略函数
命令:CREATE OR REPLACE FUNCTION fgedu_emp_policy_fn(
p_schema IN VARCHAR2,
p_object IN VARCHAR2
) RETURN VARCHAR2 IS
l_dept_id NUMBER;l_predicate VARCHAR2(2000);BEGIN
l_dept_id := SYS_CONTEXT(‘fgedu_ctx’, ‘dept_id’);IF l_dept_id IS NOT NULL THEN
l_predicate := ‘department_id = ‘ || l_dept_id;ELSE
l_predicate := ‘1=2’; — 无权限访问任何数据
END IF;RETURN l_predicate;END fgedu_emp_policy_fn;/执行:输出日志:Function created.
p_schema IN VARCHAR2,
p_object IN VARCHAR2
) RETURN VARCHAR2 IS
l_dept_id NUMBER;l_predicate VARCHAR2(2000);BEGIN
l_dept_id := SYS_CONTEXT(‘fgedu_ctx’, ‘dept_id’);IF l_dept_id IS NOT NULL THEN
l_predicate := ‘department_id = ‘ || l_dept_id;ELSE
l_predicate := ‘1=2’; — 无权限访问任何数据
END IF;RETURN l_predicate;END fgedu_emp_policy_fn;/执行:输出日志:Function created.
4.5 创建VPD策略
命令:EXEC DBMS_RLS.ADD_POLICY(
object_schema => ‘fgedu’,
object_name => ’employees’,
policy_name => ‘fgedu_emp_policy’,
function_schema => ‘fgedu’,
policy_function => ‘fgedu_emp_policy_fn’,
statement_types => ‘SELECT, INSERT, UPDATE, DELETE’
);执行:输出日志:PL/SQL procedure successfully completed.
object_schema => ‘fgedu’,
object_name => ’employees’,
policy_name => ‘fgedu_emp_policy’,
function_schema => ‘fgedu’,
policy_function => ‘fgedu_emp_policy_fn’,
statement_types => ‘SELECT, INSERT, UPDATE, DELETE’
);执行:输出日志:PL/SQL procedure successfully completed.
4.6 测试VPD效果
命令:— 设置上下文为部门90
EXEC fgedu_ctx_pkg.set_context(‘TEST_USER’, 90);– 查询员工表
SELECT employee_id, first_name, last_name, department_id FROM fgedu.employees;执行:输出日志:PL/SQL procedure successfully completed.EMPLOYEE_ID EMP_NAME EMP_EMP_EMP_LAST_NAME DEPARTMENT_ID
———– ——————– ————————- ————- 100 Steven King 90 101 Neena Kochhar 90 102 Lex De Haan 90
EXEC fgedu_ctx_pkg.set_context(‘TEST_USER’, 90);– 查询员工表
SELECT employee_id, first_name, last_name, department_id FROM fgedu.employees;执行:输出日志:PL/SQL procedure successfully completed.EMPLOYEE_ID EMP_NAME EMP_EMP_EMP_LAST_NAME DEPARTMENT_ID
———– ——————– ————————- ————- 100 Steven King 90 101 Neena Kochhar 90 102 Lex De Haan 90
4.7 测试不同部门的访问
命令:— 设置上下文为部门20
EXEC fgedu_ctx_pkg.set_context(‘TEST_USER’, 20);– 查询员工表
SELECT employee_id, first_name, last_name, department_id FROM fgedu.employees;执行:输出日志:PL/SQL procedure successfully completed.EMPLOYEE_ID EMP_NAME EMP_EMP_EMP_LAST_NAME DEPARTMENT_ID
———– ——————– ————————- ————- 201 Michael Hartstein 20
EXEC fgedu_ctx_pkg.set_context(‘TEST_USER’, 20);– 查询员工表
SELECT employee_id, first_name, last_name, department_id FROM fgedu.employees;执行:输出日志:PL/SQL procedure successfully completed.EMPLOYEE_ID EMP_NAME EMP_EMP_EMP_LAST_NAME DEPARTMENT_ID
———– ——————– ————————- ————- 201 Michael Hartstein 20
风哥提示:VPD会根据上下文自动过滤数据,确保用户只能访问授权范围内的数据
4.8 管理VPD策略
命令:— 查看VPD策略
SELECT * FROM all_policies WHERE object_owner = ‘FGEDU’ AND object_name = ‘EMPLOYEES’;– 删除VPD策略
EXEC DBMS_RLS.DROP_POLICY(‘fgedu’, ’employees’, ‘fgedu_emp_policy’);执行:输出日志:OBJECT_OWNER OBJECT_NAME POLICY_NAME PF_OWNER PF_FUNCTION SEL INS UPD DEL IDX
————– ————— ——————– ———- —————— — — — — —
FGEDU EMPLOYEES FGEDU_EMP_POLICY FGEDU FGEDU_EMP_POLICY_FN YES YES YES YES NOPL/SQL procedure successfully completed.
SELECT * FROM all_policies WHERE object_owner = ‘FGEDU’ AND object_name = ‘EMPLOYEES’;– 删除VPD策略
EXEC DBMS_RLS.DROP_POLICY(‘fgedu’, ’employees’, ‘fgedu_emp_policy’);执行:输出日志:OBJECT_OWNER OBJECT_NAME POLICY_NAME PF_OWNER PF_FUNCTION SEL INS UPD DEL IDX
————– ————— ——————– ———- —————— — — — — —
FGEDU EMPLOYEES FGEDU_EMP_POLICY FGEDU FGEDU_EMP_POLICY_FN YES YES YES YES NOPL/SQL procedure successfully completed.
更多视频教程www.fgedu.net.cn
Part05-风哥经验总结与分享
5.1 最佳实践
- 使用应用上下文存储用户信息,提高安全性和灵活性
- 合理设计安全策略函数,避免复杂的逻辑影响性能
- 为VPD过滤条件创建适当的索引,提高查询性能
- 定期审查VPD策略,确保权限控制合理
5.2 常见问题与解决方案
- 问题:VPD影响性能
解决方案:优化安全策略函数,创建适当的索引 - 问题:VPD策略冲突
解决方案:仔细设计策略,避免冲突 - 问题:应用上下文未正确设置
解决方案:确保在访问数据前正确设置上下文
学习交流加群风哥QQ113257174
5.3 性能优化
- 使用绑定变量,减少硬解析
- 避免在安全策略函数中执行复杂查询
- 考虑使用Oracle的分区功能,减少VPD的开销
- 定期监控VPD对性能的影响
更多学习教程公众号风哥教程itpux_com
5.4 安全建议
- 使用强密码保护VPD相关的包和函数
- 限制对VPD策略的修改权限
- 定期审计VPD策略的使用情况
- 结合其他安全特性,如审计和数据加密
from oracle:www.itpux.com
