利用Oracle虚拟私有数据库进行整合




        【IT168 技术】Oracle虚拟私有数据库(Virtual Private Database,下文简称VPD)是Oracle数据库产品中提供的一个安全功能,它能够保证Oracle数据库的多租户特性,与此同时,可以帮助用户进行数据库的整合。

  Oracle VPD能够针对数据库表和视图,在行与列级别对数据访问进行控制。从名称来看,Oracle VPD表达的意思多少有些误导的嫌疑,毕竟Oracle数据库已经是一个多用户的数据库,每个用户也许没有意识到他们正在共享数据库。因此,将Oracle VPD称为虚拟私有模式对象(Virtual Private Schema Object,VPSO)更为贴切,因为它会在数据库内将表、视图以及同义词进行虚拟化。但是在本文中,我们还是现将其称为VPD。

  鉴于Oracle的用户/角色安全权限模型允许访问模式对象,因此VPD将通过访问策略来强制对模式对象数据的细粒度访问。当访问策略开始执行,VPD将会动态地调整SQL语句,如SELECT、UPDATE和INSERT,其方式就是加一个WHERE条件来过滤结果。VPD不仅对用户是透明的,而且它的安全性是无法被忽视的。在Oracle企业版数据库产品中,VPD选项还是免费提供的。

  在下文要提到的VPD用例中,将介绍它如何在同一个模式下存储多个公司的数据。

使用Oracle VPD

  在许多初创的公司中,口香糖生产公司ABC看到了商机,希望能够借助托管的业务系统来迅速占领市场。他们决定建立一个客户信息系统(CIS)作为集中的网络托管与数据服务应用。为了让这个基于云的SaaS交付模型能够取得成功,他们必须整理一套解决方案,能够不修改现有的应用代码,并提供数据安全性保障,并快速地进行测试,将投资回报率最大化。

  公司的IT团队否定了为每个客户端部署单独的数据库策略,因为这样做无法满足所有的需求。因此他们开始考虑共享一个单独的数据库,其中数据库负责人建议在同一个数据库模式下用Oracle VPD存储多客户数据。他解释了VPD对于应用是完全透明的,能够提供行级数据安全,满足销售团队的灵活性需求,它是最划算的部署策略。他解释了客户为何无法认识到他们在共享一个模式对象。

多实例虚拟化数据库方案 虚拟数据库是什么_数据

  此外,他还描述了设计的主要组件是如何部署的(表1)。首先,用户将继续使用特定客户端连接池作为一个代理,通过现有的Web应用来连接到数据库。当数据库会话建立之后,一个应用语境将被设置来高效地捕获客户端标识符属性。安全性访问策略将基于一个策略函数,它将应用到模式对象中以强制客户端数据的逻辑分离。策略函数将使用应用语境和一个客户端标识列来返回一个条件限制行,访问CIS的表、视图以及同义词。



#div_code img{border:0px;}<!-- 
   

Code highlighting produced by Actipro CodeHighlighter (freeware) 
   
http://www.CodeHighlighter.com/ 
   
--> 
     表1:ABC的VPD设置

   
   -- 
   以数据库VPD管理员身份登录 
   
 
   
   
   -- 
   创建一个应用语境持有客户端标识符 
   
 
   
   
   create 
    context client_ctx using client_ctx_pkg;

  context CLIENT_CTX created.

   
   -- 
   创建一个PL/SQL包对应用语境进行设置 
   
 
   
   
   create 
     
   or 
     
   replace 
    package client_ctx_pkg  
   is 
     
   procedure 
    set_client_id;  
   end 
   ;

   
   / 
   

   
   create 
     
   or 
     
   replace 
    package body client_ctx_pkg  
   is 
     
   procedure 
    set_client_id  
   as 
    client_id  
   number 
   ;

   
   begin 
   

   
   select 
    client_id  
   into 
    client_id

   
   from 
    CIS.client  
   where 
    client_name  
   = 
    sys_context( 
   ' 
   userenv 
   ' 
   ,  
   ' 
   session_user 
   ' 
   );

  dbms_session.set_context( 
   ' 
   client_ctx 
   ' 
   ,  
   ' 
   client_id 
   ' 
   , client_id);

  exception

   
   when 
    no_data_found  
   then 
     
   null 
   ;

   
   end 
   ;

   
   end 
   ;

   
   / 
   

  PACKAGE client_ctx_pkg compiled

  PACKAGE BODY client_ctx_pkg compiled

   
   -- 
   创建一个登录触发器以运行应用语境PL/SQL包 
   
 
   
   
   create 
     
   trigger 
    set_client_id_ctx_trg after logon  
   on 
     
   database 
   

   
   begin 
   

  client_ctx_pkg.set_client_id;

   
   end 
   ;

   
   / 
   

   
   TRIGGER 
    set_client_id_ctx_trg compiled

   
   -- 
   创建一个PL/SQL策略函数来限制数据访问 
   
 
   
   
   create 
     
   or 
     
   replace 
     
   function 
    filter_client_data( schema_p  
   in 
     
   varchar2 
   , table_p  
   in 
     
   varchar2 
   )

   
   return 
     
   varchar2 
   

   
   as 
    client_predicate  
   varchar2 
    ( 
   100 
   );

   
   begin 
   

  client_predicate : 
   = 
     
   ' 
   client_id = sys_context( 
   '' 
   client_ctx 
   '' 
   ,  
   '' 
   client_id 
   '' 
   ) 
   ' 
   ;

   
   return 
    client_predicate;

   
   end 
   ;

   
   / 
   

   
   FUNCTION 
    filter_client_data compiled

   
   -- 
   基于策略函数创建一个安全性策略并应用到客户表 
   
 
   
   
   begin 
   

  dbms_rls.add_policy (object_schema  
   => 
     
   ' 
   cis 
   ' 
   

  , 
   object_name 
     
   => 
     
   ' 
   customer 
   ' 
   

  ,policy_name  
   => 
     
   ' 
   client_policy 
   ' 
   

  ,function_schema  
   => 
     
   ' 
   vpd_admin 
   ' 
   

  ,policy_function  
   => 
     
   ' 
   filter_client_data 
   ' 
   

  );

   
   end 
   ;

   
   / 
   

  anonymous block completed



  设置好了,VPD现在可以动态地添加条件到每一个查询,并高效地过滤每一个客户端的数据(表2)。



#div_code img{border:0px;}<!-- 
  

Code highlighting produced by Actipro CodeHighlighter (freeware) 
  
http://www.CodeHighlighter.com/ 
  
--> 
    表2:ABC运行VPD

   
  -- 
  1.作为一个Big Bubble Company用户,选择你的客户 
  
 
  
   
  select 
   customer_name  
  from 
   CIS.customer;

  CUSTOMER_NAME

   
  -- 
  ---------------------------- 
  
 
  
  The Gum Shop

  Jaime’s Candy

  Shannon’s Pharmacy

   
  -- 
   2. 作为一个Chew IT Enterprises 用户,选择你的客户 
  
 
  
   
  select 
   customer_name  
  from 
   CIS.customer;

  CUSTOMER_NAME

   
  -- 
  ---------------------------- 
  
 
  
  Sweet Tooth

  Gum Emporium

   
  -- 
  确认VPD动态添加一个条件到每个查询 
  
 
  
  explain  
  plan 
  

   
  set 
   statement_ID  
  = 
    
  ' 
  XXX 
  ' 
  

   
  for 
    
  select 
    
  * 
    
  from 
   CIS.customer;

   
  select 
    
  * 
    
  from 
    
  table 
  (dbms_xplan.display( 
  ' 
  PLAN_TABLE 
  ' 
  , 
  ' 
  XXX 
  ' 
  , 
  ' 
  TYPICAL 
  ' 
  ));

   
  -- 
  ---------------------------------------------------------------------------- 
  
 
  
   
  | 
   Id  
  | 
   Operation  
  | 
   Name  
  | 
   Rows  
  | 
   Bytes  
  | 
   Cost ( 
  % 
  CPU) 
  | 
   Time  
  | 
  

   
  -- 
  ---------------------------------------------------------------------------- 
  
 
  
   
  | 
    
  0 
    
  | 
    
  SELECT 
   STATEMENT  
  | 
    
  | 
    
  2 
    
  | 
    
  60 
    
  | 
    
  3 
   ( 
  0 
  ) 
  | 
    
  00 
  : 
  00 
  : 
  01 
    
  | 
  

   
  |* 
    
  1 
    
  | 
    
  TABLE 
   ACCESS  
  FULL 
  | 
   CUSTOMER  
  | 
    
  2 
    
  | 
    
  60 
    
  | 
    
  3 
   ( 
  0 
  ) 
  | 
    
  00 
  : 
  00 
  : 
  01 
    
  | 
  

   
  -- 
  ---------------------------------------------------------------------------- 
  
 
  
  Predicate Information (identified  
  by 
   operation id):

   
  -- 
  ------------------------------------------------- 
  
 
  
   
  1 
    
  - 
   filter("CLIENT_ID" 
  = 
  TO_NUMBER(SYS_CONTEXT( 
  ' 
  client_ctx 
  ' 
  , 
  ' 
  client_id 
  ' 
  )))