使用虚拟专用数据库限制数据访问
使用虚拟专用数据库限制数据访问
本教程的目标是演示虚拟专用数据库的强大数据访问限制功能,限定特定的用户访问特定数据。
大约 30 分钟
本教程包括下列主题:
将光标置于此图标上以加载和查看本教程的所有屏幕截图。(警告:此操作会同时加载所有屏幕截图,网速较慢时,响应时间可能会比较长。)
注意:此外,还可以在下列步骤中将光标放在每个单独的图标上,从而仅加载和查看与该步骤相关的屏幕截图。
虚拟专用数据库 (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 策略,限制内部用户(员工)和外部用户(客户)只访问各自的信息。执行以下步骤:
| 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; /

|
返回主题列表
现在,您可以测试该策略。执行以下步骤:
| 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;

|
返回主题列表
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 表。
|
返回主题列表
在本部分中,您将启用并应用一个相关列和列筛选 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; /

|
返回主题列表
现在,您可以测试该策略。执行以下步骤:
| 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 的所有信贷限额。
|
返回主题列表
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 策略 |
返回主题列表
|