使用虚拟专用数据库限制数据访问

目的

本教程的目标是 演示虚拟专用数据库的强大数据访问限制功能,限定特定的用户访问特定数据。

所需时间

大约 30 分钟

主题

本教程包括下列主题:

 概述
 情景

设置

 启用针对 ORDERS 表的 VPD 策略
 测试针对 ORDERS 表的 VPD 策略
 查看针对 ORDERS 表的策略
 启用针对 CUSTOMERS 表的相关列和列筛选 VPD 策略
 在 CUSTOMERS 表上测试 VPD 策略
 在 CUSTOMERS 表上查看策略
 清理
 总结

查看屏幕截图

 将光标置于此图标上以加载和查看本教程的所有屏幕截图。(警告:此操作会同时加载所有屏幕截图,网速较慢时,响应时间可能会比较长。)

注意:此外,还可以在下列步骤中将光标放在每个单独的图标上,从而仅加载和查看与该步骤相关的屏幕截图。

概述

虚拟专用数据库 (VPD) 提供了角色和视图无法提供的行级访问控制。对于互联网访问,虚拟专用数据库可以确保在线银行的客户只能看到他们自己的帐户。Web 托管公司可以在同一 Oracle 数据库中维护多个公司的数据,但只允许每个公司查看其自身数据。

在企业内部,虚拟数据库可在应用程序部署方面降低拥有成本。可以在数据库服务器一次实现安全性,而不用在访问数据的每个应用程序中分别实现安全性。因为是在数据库中实施安全性,所以不管用户访问数据的方式如何,安全性较以前更高。访问即席查询工具或新报表生成程序的用户不再能绕过安全环节。虚拟专用数据库是一项重要技术,使企业能够构建托管的、基于 Web 的应用程序。实际上,许多 Oracle 应用程序本身使用 VPD 实施数据分隔,包括 Oracle SalesOnline.com 和 Oracle Portal 等程序。

虚拟专用数据库如何工作

将一个或多个安全策略与表或视图关联后,就可以实现虚拟专用数据库。对带安全策略的表进行直接或间接访问时,数据库将调用一个实施该策略的函数。策略函数返回一个访问条件(WHERE 子句),即谓词。应用程序将它附加到用户的 SQL 语句,从而动态修改用户的数据访问权限。

你可以通过编写一个存储过程将 SQL 谓词附加到每个 SQL 语句(用于控制该语句的行级别访问权限)来实施 VPD。例如,如果 John Doe(他属于 Department 10)输入 SELECT * FROM emp 语句,则可以使用 VPD 添加 WHERE DEPT = 10 子句。这样,您便可以通过对查询进行修改来限制访问某些行的数据。

虚拟专用数据库确保无论用户以何种方式访问数据(通过应用程序、报表编写工具或 SQL*Plus),都将强制实施同一强大的访问权限控制策略。这样,使用 VPD ,银行便可以确保客户只看到他们自己的帐户,电信公司可以安全地隔离客户记录,人力资源应用程序可以支持复杂的员工记录数据访问原则。

返回主题列表

应用案例

在本教程中,您将创建两个不同的管理员用户:

sec_admin

该用户将创建策略函数,将策略应用于表并为该表创建索引以提高性能。

 

hr_sec

该用户在验证 CUSTOMERS 或 EMPLOYEES 表中包含某些数据库用户和角色后,将创建这些数据库用户和角色。

 

返回主题列表

设置

在本教程中,您将创建一组用户和角色来演示 VPD 如何工作。要创建用户和角色,请执行以下步骤:

1.

打开一个终端窗口,执行以下命令:

                               
                                 
cd /home/oracle/wkdir
sqlplus /nolog
@create_admin_users_and_roles
                              
                            
set echo off
                              
prompt *** Create admin users: sec_admin and hr_sec
prompt
connect / as sysdba
grant connect, create procedure to sec_admin identified by welcome1;
grant execute on sys.dbms_rls to sec_admin;
grant connect, create user, drop user, create role, drop any role
to hr_sec identified by welcome1;
prompt
prompt ***** Create roles: employee_role and customer_role
connect hr_sec/welcome1;
create role employee_role;
create role customer_role;

prompt ***** Grant system and object privileges to roles and users
connect system/oracle;
grant connect to employee_role;
grant connect to customer_role;
connect oe/oe;
grant select on oe.orders to employee_role;
grant select on oe.orders to customer_role;
grant select on oe.customers to sec_admin;
grant select on oe.customers to employee_role;
connect hr/hr;
grant select on hr.employees to sec_admin;
connect hr_sec/welcome1;
prompt ***** Create Steven King (President) create user SKING identified by welcome1;
grant employee_role to SKING;
prompt ***** Create Karen Partners (Sales Manager rep. to SKing)
create user KPARTNER identified by welcome1;
grant employee_role to KPARTNER;
prompt ***** Create Louise Doran (Sales Rep in Karen Partners team)
create user LDORAN identified by welcome1;
grant employee_role to LDORAN;
prompt ***** Create Eleni Zlotkey (another Sales Manager)
create user EZLOTKEY identified by welcome1;
grant employee_role to EZLOTKEY;
prompt ***** Create Matthias Hannah (Customer)
create user "MATTHIAS.HANNAH@GREBE.COM" identified by welcome1;
grant customer_role to "MATTHIAS.HANNAH@GREBE.COM";

 

返回主题列表

在 ORDERS 表上启用 VPD 策略

您将在 ORDERS 表上应用 VPD 策略,限制内部用户(员工)和外部用户(客户)只访问各自的信息。执行以下步骤:

1.

从终端窗口中,执行以下脚本:

                               
                                 
@enable_vpd_policy
                              
                            

The enable_vpd_policy.sql script contains the following:

                               
connect sec_admin/welcome1;
                              
prompt *** Create policy function to be called when 'ORDERS' table is accessed
create or replace function f_policy_orders
-- Function must have the following parameters
(schema in varchar2, tab in varchar2)
-- Function will return a string that is used as a WHERE clause
return varchar2
as
v_employee_id number:=0;
v_customer_id number:=0;
is_sales_rep number:=0;
is_sales_manager number:=0;
is_president number:=0;
is_customer number:=0;
is_employee number:=0;
v_job_id varchar2(20);
v_user varchar2(100);
out_string varchar2(400) default '1=2 ';
-- out_string will be the return value.
-- It is initialized to '1=2' because 'WHERE 1=2' means
-- 'Nothing to access' and this can be combined with
-- other conditions by OR
begin
-- get session user
v_user := lower(sys_context('userenv','session_user'));
-- Is the user a customer?
begin
select customer_id into v_customer_id from oe.customers where lower(cust_email) = v_user;
is_customer:=1;
exception
when no_data_found then
v_customer_id := 0;
end;
-- Is the user an employee?
begin
select employee_id,job_id into v_employee_id,v_job_id from hr.employees where lower(email) = v_user;
is_employee:=1;
exception
when no_data_found then
v_employee_id := 0;
end;
-- get role of employee if user is an employee
if v_employee_id != 0 and v_job_id='SA_REP' then
-- User is Sales Rep
is_sales_rep := 1;
elsif v_employee_id != 0 and v_job_id='SA_MAN' then
-- User is Sales Manager
is_sales_manager := 1;
elsif v_employee_id != 0 and v_job_id='AD_PRES' then
-- User is President
is_president := 1;
end if;
-- Now create the string to be used as the WHERE clause. If the user is e.g. sales rep and customer, both conditions are valid.
if is_president = 1 or v_user='oe' then
-- The president and the owner of the table (OE) are allowed to see all orders (WHERE 1=1 or anything) means all rows
out_string := out_string||'or 1=1 ';
end if;
if is_customer = 1 then
-- Customers are allowed to see their orders only
out_string := out_string||'or customer_id = '||v_customer_id||' ';
end if;
if is_sales_rep = 1 then
-- Sales Reps are allowed to see orders they have worked on
out_string := out_string||'or sales_rep_id = '||v_employee_id||' ';
end if;
if is_sales_manager = 1 then
-- Sales Managers are allowed to see orders of customers who belong to their Sales Reps;
-- In this case the WHERE clause needs a subquery in order to find if their sales reps have any customers in the orders table:
out_string := out_string||'or sales_rep_id in (select employee_id from hr.employees where manager_id = '||v_employee_id||')';
end if;
-- If the user is none of the above the WHERE clause will be (WHERE 1=2), the default and that means nothing to access
return out_string;
end;
/

 

2.

从终端窗口中,执行以下脚本:

                               
                                 
@apply_vpd_policy
                              
                            

The apply_vpd_policy.sql script contains the following:

begin
                              
dbms_rls.add_policy('oe','orders','accesscontrol_orders','sec_admin', 'f_policy_orders',policy_type => dbms_rls.context_sensitive);
end;
/

 

返回主题列表

测试针对 ORDERS 表的 VPD 策略

现在,您可以测试该策略。执行以下步骤:

1.

用户 Matthias 的 CUSTOMER_ID 为 106。安全性策略根据 CUSTOMERS 表在应用程序上下文中验证他的登录名,然后只允许访问 ORDERS 表中他自己的订单。从终端窗口中,执行以下脚本:

                               
                                 
@select_orders_as_matthias

connect "MATTHIAS.HANNAH@GREBE.COM"/welcome1;
                                
select ORDER_ID, ORDER_TOTAL, CUSTOMER_ID from oe.orders;

 

2.

Louise Doran 是一位 EMPLOYEE_ID=160 的销售代表。您将运行一个查询,以只显示她自己的客户下的订单。从终端窗口中,执行以下脚本:

                               
                                 
@select_orders_as_ldoran

connect LDORAN/welcome1;
                                
select ORDER_ID, CUSTOMER_ID, ORDER_TOTAL, SALES_REP_ID from oe.orders;

 

3.

Karen Partner 是一位 EMPLOYEE_ID=146 的销售经理。您将运行一个查询,以只显示她的销售代表团队的客户下的订单。从终端窗口中,执行以下脚本:

                               
                                 
@select_orders_as_kpartner

connect KPARTNER/welcome1;
                                
select ORDER_ID, CUSTOMER_ID, ORDER_TOTAL, SALES_REP_ID from oe.orders order by sales_rep_id;

 

4.

您将以 OE 所有者的身份运行一个查询,以查看 ORDERS 表中的订单数量。从终端窗口中,执行以下脚本:

                               
                                 
@select_count_orders_as_oe

connect oe/oe;
                                
select count(*) from oe.orders;

 

5.

现在,以 Steven King 的身份运行同一查询。 注意,结果是一个相同的数字,并且他可以查看所有订单。 这是因为他是总裁,因此可以查看所有内容。从终端窗口中,执行以下脚本:

                               
                                 
@select_count_orders_as_sking

connect SKING/welcome1;
                                
select count(*) from oe.orders;

 

返回主题列表

查看针对 ORDERS 表的策略

VPD 策略将 WHERE 子句附加到所有对受保护表的查询。 要验证 WHERE 子句是否正确(您的审计员可能会询问此问题),请执行以下步骤:

1.

从终端窗口中,执行以下脚本:

                               
                                 
@vpd_where_clause_orders
                              
                            
connect system/oracle
                              
select predicate as "predicate (WHERE clause)" from v$vpd_policy where object_name='ORDERS';

注意: 将策略应用于该表后,将根据策略函数中定义的 WHERE 子句筛选授权用户执行的所有查询。 为提高性能,可以对 WHERE 子句中使用的列上的受保护表应用索引。 在本教程中,默认情况下已经将多个索引应用于 ORDERS 表。

 

返回主题列表

启用针对 CUSTOMERS 表的相关列和列筛选 VPD 策略

在本部分中,您将启用并应用一个相关列和列筛选 VPD 策略。 该策略应用于 CUSTOMERS 表,以便只有员工可以访问他们实际所需的信息。 客户将不被授予任何访问权限。 机密信息(例如,CREDIT_LIMIT)的访问权限由策略规定。执行以下步骤:

1.

从终端窗口中,执行以下脚本:

                               
                                 
@enable_vpd_policy2

                                
connect sec_admin/welcome1;
                                
                                   
create or replace function f_policy_customers
-- Function must have the following parameters
(schema in varchar2, tab in varchar2)
-- Function will return a string that is used as a WHERE clause
return varchar2
as
v_employee_id number:=0;
is_sales_manager number:=0;
is_sales_rep number:=0;
is_president number:=0;
is_employee number:=0;
v_job_id varchar2(20);
v_user varchar2(100);
out_string varchar2(400) default '1=2 ';
-- out_string will be the return value.
-- It is initialized to '1=2' because 'WHERE 1=2' means
-- 'Nothing to access' and this can be combined with
-- other conditions by OR
begin
-- get session user
v_user := lower(sys_context('userenv','session_user'));
begin
select employee_id,job_id into v_employee_id,v_job_id from hr.employees where lower(email) = v_user;
is_employee:=1;
exception
when no_data_found then
v_employee_id := 0;
end;
-- get role of employee:
if v_employee_id != 0 and v_job_id='SA_MAN' then
-- User is Sales Manager
is_sales_manager := 1;
elsif v_employee_id != 0 and v_job_id='AD_PRES' then
-- User is President
is_president := 1;
end if;
-- Now create the string to be used as the WHERE clause;
if is_president = 1 or v_user='oe' then
-- The president and the owner of the table (OE) are allowed to see all orders (WHERE 1=1 or anything) means all rows
out_string := out_string||'or 1=1 ';
end if;
if is_sales_manager = 1 then
-- Sales Managers are allowed to see all information about their own customers; the Credit Limit of all other customers is hidden from them:
out_string := out_string||'or ACCOUNT_MGR_ID = '||v_employee_id||'';
end if;
-- If the user is none of the above the WHERE clause will be (WHERE 1=2), the default and that means nothing to access
return out_string;
end;
/

 

2.

现在,您可以将该策略应用于表。 为提高性能,添加了参数“context_sensitive”,以便仅当应用程序上下文的内容更改时(例如,当新用户登录时)执行该函数。在终端窗口中,执行以下脚本:

                               
                                 
@apply_vpd_policy2
                              
                            
begin
                              
dbms_rls.add_policy('oe','customers','accesscontrol_customers','sec_admin', 'f_policy_customers', sec_relevant_cols=>'CREDIT_LIMIT', sec_relevant_cols_opt => dbms_rls.ALL_ROWS, policy_type => dbms_rls.context_sensitive);
end;
/

 

返回主题列表

测试针对 CUSTOMERS 表的 VPD 策略

现在,您可以测试该策略。执行以下步骤:

1.

Matthias Hannah 正在使用 customer_role,它根本不包含 CUSTOMERS 表的访问权限。在终端窗口中,执行以下脚本:

                               
                                 
@select_customers_as_matthias

connect "MATTHIAS.HANNAH@GREBE.COM"/welcome1;
                                
select * from oe.customers;

 

2.

Eleni Zlotkey 是一位 EMPLOYEE_ID=149 的销售经理。她将只能查看她所负责的客户的信贷限额, 而看不到所有其他信贷限额。在终端窗口中,执行以下脚本:

                               
                                 
@select_customers_as_ezlotkey

connect EZLOTKEY/welcome1;
                                
select CUST_FIRST_NAME, CUST_LAST_NAME, CREDIT_LIMIT, ACCOUNT_MGR_ID from oe.customers order by ACCOUNT_MGR_ID;

向上稍稍滚动可以看到另一个 ACCOUNT_MGR_ID。注意,信贷限额已被隐藏。

 

3.

您将运行一个查询以查看 Steven King 的客户列表。 由于他是总裁,因此可以看到所有内容。在终端窗口中,执行以下脚本:

                               
                                 
@select_customers_as_sking

connect SKING/welcome1;
                                
select CUST_FIRST_NAME, CUST_LAST_NAME, CREDIT_LIMIT, ACCOUNT_MGR_ID from oe.customers order by ACCOUNT_MGR_ID;

向上稍稍滚动可以看到,Steven King 可以查看任何 ACCOUNT_MGR_ID 的所有信贷限额。

 

返回主题列表

查看针对 CUSTOMERS 表的策略

VPD 策略将 WHERE 子句附加到所有针对受保护表的查询。 要验证 WHERE 子句是否正确(您的审计员可能会询问此问题),请执行以下步骤:

1.

在终端窗口中,执行以下脚本:

                               
                                 
@vpd_where_clause_customers
                              
                            
connect system/oracle
                              
select predicate as "predicate (WHERE clause)" from v$vpd_policy where object_name='CUSTOMERS';

注意: 将策略应用于该表后,将根据策略函数中定义的 WHERE 子句筛选授权用户执行的所有查询。 为提高性能,可以对 WHERE 子句中使用的列上的受保护表使用索引。 在本教程中,默认情况下已经将多个索引应用于 CUSTOMERS 表。

 

返回主题列表

清理

执行以下步骤以清理数据库:

1.

在终端窗口中,执行以下脚本:

                               
                                 
@vpd_cleanup
                              
                            
                               
connect hr_sec/welcome1;
                              
                                 
drop user SKING cascade;
drop user KPARTNER cascade;
drop user LDORAN cascade;
drop user EZLOTKEY cascade;
drop user "MATTHIAS.HANNAH@GREBE.COM" cascade;
drop role employee_role;
drop role customer_role;

connect sec_admin/welcome1;
execute dbms_rls.drop_policy('oe','orders','accesscontrol_orders');
execute dbms_rls.drop_policy('oe','customers','accesscontrol_customers');
drop function f_policy_orders;
drop function f_policy_customers;

connect / as sysdba;
drop user sec_admin cascade;
drop user HR_sec cascade;

 

返回主题列表

总结

在本教程中,您学习了如何执行下列任务:

 启用 VPD 策略
 查看策略
 应用带有相关列和列筛选的 VPD 策略

返回主题列表

 将光标置于该图标上可以隐藏所有屏幕截图。

Left Curve
热门下载
Right Curve
Left Curve
更多融合中间件下载
Right Curve