使用VPD限制数据访问

一    概述
   虚拟专用数据库 (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 ,银行便可以确保客户只看到他们自己的帐户,电信公司可以安全地隔离客户记录,人力资源应用程序可以支持复杂的员工记录数据访问原则。

DBMS_RLS Procedures

Procedure Description

For Handling Individual Policies


DBMS_RLS.ADD_POLICY

Adds a policy to a table, view, or synonym

DBMS_RLS.ENABLE_POLICY

Enables (or disables) a policy you previously added to a table, view, or synonym

DBMS_RLS.REFRESH_POLICY

Invalidates cursors associated with nonstatic policies

DBMS_RLS.DROP_POLICY

To drop a policy from a table, view, or synonym

For Handling Grouped Policies


DBMS_RLS.CREATE_POLICY_GROUP

Creates a policy group

DBMS_RLS.DELETE_POLICY_GROUP

Drops a policy group

DBMS_RLS.ADD_GROUPED_POLICY

Adds a policy to the specified policy group

DBMS_RLS.ENABLE_GROUPED_POLICY

Enables a policy within a group

DBMS_RLS.REFRESH_GROUPED_POLICY

Parses again the SQL statements associated with a refreshed policy

DBMS_RLS.DISABLE_GROUPED_POLICY

Disables a policy within a group

DBMS_RLS.DROP_GROUPED_POLICY

Drops a policy that is a member of the specified group

For Handling Application Contexts


DBMS_RLS.ADD_POLICY_CONTEXT

Adds the context for the active application

DBMS_RLS.DROP_POLICY_CONTEXT

Drops the context for the application

三    创建静态的VPD

1    激活OE用户

   SELECT USERNAME, ACCOUNT_STATUS FROM DBA_USERS WHERE USERNAME = 'OE';

   ALTER USER OE ACCOUNT UNLOCK IDENTIFIED BY test;


2、创建策略,只查询表OE.ORDERS中SALES_REP_ID = 159用户的记录。

(1)创建策略前

   SELECT * FROM OE.ORDERS;    

   SELECT * FROM OE.ORDERS  WHERE SALES_REP_ID = 159;

(2)创建策略函数auth_orders

CREATE OR REPLACE FUNCTION auth_orders(
  schema_var IN VARCHAR2,
  table_var  IN VARCHAR2
 )
 RETURN VARCHAR2
 IS
  return_val VARCHAR2 (400);
 BEGIN
  return_val := 'SALES_REP_ID = 159';
  RETURN return_val;
 END auth_orders;

(3)创建VPD策略

BEGIN
  DBMS_RLS.ADD_POLICY (
    object_schema    => 'oe',
    object_name      => 'orders',
    policy_name      => 'orders_policy',
    function_schema  => 'sys',
    policy_function  => 'auth_orders',
    statement_types  => 'select, insert, update, delete'
   );
END;

    备注:object_schema表示数据表(视图)object_name所在的方案名称,object_name表示数据表(视图)的名称,policy_name表示给策略取得名称,方便对策略进行管理,function_schema表示返回Where子句的函数所在方案的名称,policy_function表示返回Where子句的函数名称,statement_types表示要使用该策略的DML类型,如:select, insert, update, delete等。


3    测试

   使用OE登录,输入如下语句:

SELECT Count(*) FROM ORDERS;

   返回值为7。

   切换到sys用户登录。输入如下语句:

SELECT Count(*) FROM OE.ORDERS;

   返回值为105,说明VPD策略起作用。


4     删除策略函数和策略

以sys用户登录,输入如下命令:

    DROP FUNCTION auth_orders;

   EXEC DBMS_RLS.DROP_POLICY('OE','ORDERS','ORDERS_POLICY');


四 创建基于上下文相关的VPD

1    创建VPD策略管理员用户sysadmin_vpd并授权

GRANT CREATE SESSION, CREATE ANY CONTEXT, CREATE PROCEDURE, CREATE TRIGGER, ADMINISTER DATABASE TRIGGER TO sysadmin_vpd IDENTIFIED BY 密码;
GRANT EXECUTE ON DBMS_SESSION TO sysadmin_vpd;
GRANT EXECUTE ON DBMS_RLS TO sysadmin_vpd;


2    激活scott用户

SELECT USERNAME, ACCOUNT_STATUS FROM DBA_USERS WHERE USERNAME = 'SCOTT';
ALTER USER SCOTT ACCOUNT UNLOCK IDENTIFIED BY 密码;


3     创建(上下文用户)数据库登录用户数据表scott.customes,登录用户名是cust_email字段的值

CREATE TABLE scott.customers (
 cust_no    NUMBER(4),
 cust_email VARCHAR2(20),
 cust_name  VARCHAR2(20));
                                                                                                                                                                                                                                                                                                                                                                                                                                                                            
INSERT INTO scott.customers VALUES (1234, 'TBROOKE', 'Thadeus Brooke');
INSERT INTO scott.customers VALUES (5678, 'OWOODS', 'Oberon Woods');


4    创建测试用户

GRANT CREATE SESSION TO tbrooke IDENTIFIED BY 密码;
GRANT CREATE SESSION TO owoods IDENTIFIED BY 密码;


5    将scott.customers表select权限授权给sysadmin_vpd(该表不需要授权给数据库登录用户tbrookeowoods,只是存储过程需要使用该表)

GRANT SELECT ON scott.customers TO sysadmin_vpd;


6    创建样例测试数据表scott.orders_tab,该表中的cust_no字段和scott.customers.cust_no一一对用

CREATE TABLE scott.orders_tab (
  cust_no  NUMBER(4),
  order_no NUMBER(4));
INSERT INTO scott.orders_tab VALUES (1234, 9876);
INSERT INTO scott.orders_tab VALUES (5678, 5432);
INSERT INTO scott.orders_tab VALUES (5678, 4592);


7    将该表授权给数据库登录用户tbrooke和owoods

GRANT SELECT ON scott.orders_tab TO tbrooke;
GRANT SELECT ON scott.orders_tab TO owoods;


8    创建基于会话的应用程序上下文(以sysadmin_vpd用户登录

   以使用create context命令创建应用程序上下文,并且使用程序包DBMS_RLS管理VPD策略。可以像其他任何函数一样创建用于返回谓词以实施策略的函数,但这种函数具有两个必需的参数,并且返回一个VARCHAR2。

   使用create context命令,可以创建应用程序定义的属性的名称,这些属性用于实施安全策略。此外,还可以定义函数和过程的程序包名称,这些函数和过程用于设置用户会话的安全上下文。

   以sysadmin_vpd用户登录,创建如下内容:

CREATE OR REPLACE CONTEXT orders_ctx USING orders_ctx_pkg;


CREATE OR REPLACE PACKAGE orders_ctx_pkg IS
  PROCEDURE set_custnum;
END;


CREATE OR REPLACE PACKAGE BODY orders_ctx_pkg IS
  PROCEDURE set_custnum
  AS
    custnum NUMBER;
  BEGIN
     SELECT cust_no INTO custnum FROM SCOTT.CUSTOMERS
        WHERE cust_email = SYS_CONTEXT('USERENV', 'SESSION_USER');
     DBMS_SESSION.SET_CONTEXT('orders_ctx', 'cust_no', custnum);
  EXCEPTION
   WHEN NO_DATA_FOUND THEN NULL;
  END set_custnum;
END;

   在该示例中,上下文名称是orders_ctx,用于在会话期间为用户建立特征或属性的程序包称为orders_ctx_pkg。在登录触发器中调用过程set_custnum。因为上下文orders_ctx只绑定到orders_ctx_pkg,因此没有其他的过程可以改变会话属性。这可以确保在连接到数据库后用户或任何其他进程都不可以改变安全的应用程序上下文。

   在用于实现应用程序上下文的典型程序包中,使用内置的上下文USERENV来检索有关用户会话自身的信息。下表是USERENV上下文中一些更为常见的参数。

   参

  返

CURRENT_SCHEMA

会话的默认模式

DB_NAME

在初始参数DB_NAME中指定的数据库名称

HOST

用户连接的主机名称

IP_ADDRESS

用户连接的IP地址

OS_USER

初始化数据库会话的操作系统账户

SESSION_USER

经过验证的数据库用户名


DBMS_SESSION.SET_CONTEXT (

namespace VARCHAR2,

attribute VARCHAR2,

value VARCHAR2,

username VARCHAR2,

client_id VARCHAR2 );

参数的含义:

namespace 这个上下文的名字

attribute 属性值,即为key值

value 值

username 用户名 默认null,可选值

client_id 指定的clientid 默认null,可选值

    备注:在该实例中给DBMS_SESSION.SET_CONTEXT('orders_ctx', 'cust_no', custnum)含义是:给上下文orders_ctx中的SYS_CONTEXT增加一个属性,属性名为cust_no,属性值为便利custnum的值。以后再上下文orders_ctx中就可以通过SYS_CONTEXT(''orders_ctx'', ''cust_no'')来获得属性cust_no的值。


9    创建登录触发器(以sysadmin_vpd用户登录)

   以sysadmin_vpd用户登录,创建如下触发器:

CREATE TRIGGER set_custno_ctx_trig AFTER LOGON ON DATABASE
BEGIN
 sysadmin_vpd.orders_ctx_pkg.set_custnum;
END;

   只有在应用程序上下文中用户登录才能触发该触发器。可以使用如下命令查看:

    SELECT SYS_CONTEXT('orders_ctx', 'cust_no') custnum FROM DUAL;

10    创建策略函数get_user_orders,只显示登录用户的订单(以sysadmin_vpd用户登录)

CREATE OR REPLACE FUNCTION get_user_orders(
  schema_p   IN VARCHAR2,
  table_p    IN VARCHAR2)
 RETURN VARCHAR2
 AS
  orders_pred VARCHAR2 (400);
 BEGIN
  orders_pred := 'cust_no = SYS_CONTEXT(''orders_ctx'', ''cust_no'')';
 RETURN orders_pred;
END;


11    创建策略(以sysadmin_vpd用户登录)

BEGIN
 DBMS_RLS.ADD_POLICY (
  object_schema    => 'scott',
  object_name      => 'orders_tab',
  policy_name      => 'orders_policy',
  function_schema  => 'sysadmin_vpd',
  policy_function  => 'get_user_orders',
  statement_types  => 'select');
END;


12    测试

   以tbrooke用户登录,结果:

wKiom1MZttnAZrR3AAEuPh6vC1s593.jpg



以owoods以后登录,结果:

wKiom1MZtwegxG_xAAEwxa_TVIM326.jpg


以scott用户登录,查询到数据为0,只有以sys用户登录,可以查询到所有数据。

查看策略应用情况:

select object_owner,object_name,policy,predicate from V$VPD_POLICY;

若需要scott用户能查询到所记录,修改策略函数为:

CREATE OR REPLACE FUNCTION get_user_orders(
  schema_p   IN VARCHAR2,
  table_p    IN VARCHAR2)
 RETURN VARCHAR2
 AS
  v_email VARCHAR2(20);
 BEGIN
  v_email := sys_context('USERENV','SESSION_USER');
  if v_email = 'SCOTT' Then
    retun null;
  else
    return 'cust_no = SYS_CONTEXT(''orders_ctx'', ''cust_no'')';
  end if;
END;

   备注:用户名“SCOTT”必须大写,否则无效。


13    删除创建的数据,回复原样

BEGIN
 DBMS_RLS.DROP_POLICY (
  object_schema    => 'scott',
  object_name      => 'orders_tab',
  policy_name      => 'orders_policy');
END;


DROP TABLE scott.orders_tab;
DROP TABLE scott.customers;
DROP CONTEXT orders_ctx;
DROP USER sysadmin_vpd CASCADE;
DROP USER tbrooke cascade;
DROP USER owoods cascade;








本文出自 “IT技术学习与交流” 博客,谢绝转载!

你可能感兴趣的:(oracle,VPD,FGAC)