使用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

1
2
3
4
5
6
7
8
9
10
11
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策略

1
2
3
4
5
6
7
8
9
10
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并授权

1
2
3
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用户

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


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

1
2
3
4
5
6
7
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    创建测试用户

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


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

1
GRANT  SELECT  ON  scott.customers  TO  sysadmin_vpd;


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

1
2
3
4
5
6
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

1
2
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用户登录,创建如下内容:

1
CREATE  OR  REPLACE  CONTEXT orders_ctx USING orders_ctx_pkg;


1
2
3
CREATE  OR  REPLACE  PACKAGE orders_ctx_pkg  IS
   PROCEDURE  set_custnum;
END ;


1
2
3
4
5
6
7
8
9
10
11
12
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用户登录,创建如下触发器:

1
2
3
4
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用户登录)

1
2
3
4
5
6
7
8
9
10
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用户登录)

1
2
3
4
5
6
7
8
9
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用户登录,可以查询到所有数据。

查看策略应用情况:

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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    删除创建的数据,回复原样

1
2
3
4
5
6
BEGIN
  DBMS_RLS.DROP_POLICY (
   object_schema    =>  'scott' ,
   object_name      =>  'orders_tab' ,
   policy_name      =>  'orders_policy' );
END ;


1
2
3
4
5
6
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 ;




     本文转自stock0991 51CTO博客,原文链接:http://blog.51cto.com/qing0991/1364386,如需转载请自行联系原作者











相关文章
|
4月前
|
关系型数据库 分布式数据库 数据库
drds跨表查询与事务处理
drds跨表查询与事务处理
42 1
|
13天前
|
存储 SQL Apache
阿里云数据库内核 Apache Doris 基于 Workload Group 的负载隔离能力解读
阿里云数据库内核 Apache Doris 基于 Workload Group 的负载隔离能力解读
阿里云数据库内核 Apache Doris 基于 Workload Group 的负载隔离能力解读
|
3月前
|
存储 SQL 关系型数据库
drds逻辑表与物理解析
drds逻辑表与物理解析
25 5
|
7月前
|
存储 数据采集 缓存
OPC接口与数据访问方法
OPC接口与数据访问方法
|
网络协议 Shell Python
跨region的智能DNS解决方案(二)-CRUD
项目背景:考虑到高可靠等诸多问题,在公有云或私有云上可能有两地三中心等多种架构模式。 需求在不同地区的实例节点如何通过相同域名解析到本地的A记录或者云产品的CNAME,并实现高可靠。 本文通过named服务实现上述功能,此外由于容器以及kubernetes的流行CoreDNS也是很好的选型在此不做赘述。
1569 0