你好,欢迎来到电脑编程技巧与维护杂志社! 杂志社简介广告服务读者反馈编程社区  
合订本订阅
 
 
您的位置:技术专栏 / Linux开发
oracle 基础(19)
 

提示
几个潜在破环性提示如下:

  • VPD 运行的方式是重写查询以添加额外的谓词。 用户查询可能写得很好,可能调整得很好,但是引入额外的谓词却带来了破坏,因为优化计划可能改变。 您应该仔细考虑潜在的影响,通过建立索引降低风险。
  • 物化视图工作的方式是从底层表中选择行。 如果视图的模式所有者不受限制就可以访问该表,则只有那些和 VPD 策略一致的行才会被刷新,使视图不精确。
  • 如果您已经设置了复制,从事传播和接收工作的用户应该可以不受限制地对表进行访问。否则,他们只能复制表中的一部分。
  • 如果您使用直接路径插入(使用 APPEND 提示插入)对该表进行加载,那么您在该表上不可能有 VPD 策略。 使用可以不受限制地对表访问的用户,您应该临时禁止该策略,或进行插入。
  • 直接路径导出跳过 SQL 层;因此,VPD 策略不会被应用。 所以,当您使用 DIRECT=Y 选项导出表时,Oracle 忽略该表,并且使用常规路径导出该表。 这可能增加整个执行时间。

操作计划

这个计划是很复杂的,也是可改变的:

  1. 识别 VPD 将保护的表。
  2. 识别需要保护的表的列。
  3. 识别限制条件,例如,Salaries > 1000。
  4. 识别如何建立权限——例如,用户具备授权级别或角色吗? 您可能希望将用户分为三组,每组都有相关的授权级别。 或者,可能您想根据角色对用户群的访问限制进行分配——经理可以访问所有的行,职员可以访问超过 SALARY > 2000 行,等等。
  5. 决定您如何通过包变量、应用程序环境,或者静态表将权限传给策略函数。
  6. 如果需要创建更多的索引,请进行识别。
  7. 创建额外的索引。
  8. 识别子表,决定一个方案来启动通过新列或 IN 条件对子表的限制。
  9. 根据以上决定重新识别对索引的需求。
  10. 创建索引。
  11. 构建策略函数。
  12. 创建策略(但是禁止)。
  13. 在某个轻松活动的一天里,启动该策略和测试,使用常规用户账户访问该表以确保该策略的运行。 如果该策略不运行,请检查跟踪文件以找到错误。
  14. 如果该策略不运行,请启动该策略。
  15. 监控性能。
  16. 识别更多需求以构建索引,使用大纲,等等。
  17. 迭代所有表。

4.3 屏蔽敏感的列

背景
把您自己想象成为一名业余数据库黑客。 这里的数据库包含医疗记录,您正在寻找的信息是诊断代码。 您将寻找哪些列? 可能是称为诊断、疾病或者类似的列。

正如您可以看到的,带有明显名字的敏感列是至关重要的安全问题。

策略
如果对手以前不了解您数据库的内容,并且这些列的名字不直观,他们将不会去解读列的含义。 这个策略称为“无名安全”。 即使故意闯进数据库的经验丰富的黑客在做其它事情之前仍将需要追捕到列的名称。 因为他们的时间可能有限——几乎一直都是这样——他们通常会转到下一个机会上。 当然,使用无名列也加大了开发的难度。

进行折衷还有其它的办法,然而: 通过列屏蔽,您可以隐藏列的内容,只有合法用户才可以看到列的内容。

列屏蔽的方法有两种: 使用视图和使用 VPD。

使用视图。 这种方法适用于 Oracle 任何版本,但是如果您的数据库版本是 Oracle9i 或者更早,就只能选择这种方法。

假设您的表和以下类似:

SQL> desc patient_diagnosis
Name                              Null?类型
 ------------------- ------ -------------
 PATIENT_ID                 NUMBER
 DIAGNOSIS_ID               NUMBER
 DIAGNOSIS_CODE             VARCHAR2(2)
 DOCTOR_ID                  NUMBER(2)
 BILLING_CODE               NUMBER(10)
行类和以下类似:
SQL> select * from patient_diagnosis;

PATIENT_ID DIAGNOSIS_ID DI  DOCTOR_ID BILLING_CODE
---------- ------------ -- ---------- ------------
         1            1 01          1         1003
         1            2 02          1         1003
         1            3 11          1         1003
         2            1 11          1         1005
         2            2 41          2         1005
在这里,您想屏蔽列 DIAGNOSIS_CODE 的值。
create view vw_patient_disgnosis
as
select
   patient_id,
   diagnosis_id,
   doctor_id,
   billing_code
from patient_diagnosis
/

然后,您可以给视图 VW_PATIENT_DIAGNOSIS 创建同义词 PATIENT_DIAGNOSIS,授予视图(而不是表)选择。 该视图屏蔽列 DIAGNOSIS_CODE。

这是一个相当简单的解决方案,因此您不要将所有用户的列屏蔽掉,您可能想创建基于角色的匿名——如果用户是一名经理,请显示被保护的列;否则的话不要显示。其方法是:传递应用程序环境或者全球变量以指定用户的角色。 如果应用程序环境属性是 IS_MANAGER,您可以使用:

create or replace view vw_patient_disgnosis
as
select
   patient_id,
   diagnosis_id,
   decode(
      sys_context('USER_ROLE_CTX','IS_MANAGER'), 
      'Y', DIAGNOSIS_CODE, null
   ) diagnosis_code,
   doctor_id,
   billing_code
from patient_diagnosis;

这是一个更加灵活的视图,该视图可以授权给所有的用户,该视图的内容会随着用户角色的不同而不同。

使用 VPD。 Oracle 数据库 10g 中引入的新特性使 VPD 更加有用: 创建视图是没有必要的。 相反,VPD 策略可能抑制显示。 这里,VPD 策略函数和以下类似:

  1  create or replace function pd_pol
  2  (
  3     p_schema        in varchar2,
  4     p_obj           in varchar2
  5  )
6  return varchar2
  7  is
  8     l_ret   varchar2(2000);
9  begin
 10     if (p_schema = USER) then
 11             l_ret := NULL;
 12     else
 13             l_ret := '1=2';
 14     end if;
 15     return l_ret;
16  end;
现在构建策略函数:
1  begin
  2     dbms_rls.add_policy (
  3         object_schema          => 'ARUP',
  4         object_name            => 'PATIENT_DIAGNOSIS',
  5         policy_name            => 'PD_POL',
  6         policy_function        => 'PD_POL',
  7         statement_types        => 'SELECT',
  8         update_check           => TRUE,
  9         sec_relevant_cols      => 'DIAGNOSIS_CODE',
 10         sec_relevant_cols_opt  => dbms_rls.all_rows
 11     );
12  end;

注意行号 9 和 10。在第 9 行中,我们提及将列 DIAGNOSIS_CODE 作为敏感列。 在第 10 行中,我们指出如果选择了该列,VPD 显示所有列;但是该列值却显示为 NULL。 这就有效地屏蔽了该列。 在策略函数中,请注意如果表的所有者进行选择,应用的谓词为 NULL。因此,VPD 限制就不被应用,列也不显示。

请记住,没有“更换”策略的方法。 如果旧策略还存在,您必须首先抛弃旧策略。

begin
    dbms_rls.drop_policy (
        object_schema      => 'ARUP',
        object_name        => 'PATIENT_DIAGNOSIS',
        policy_name        => 'PD_POL'
    );
end;
现在,您可以进行测试。
SQL> conn arup/arup
Connected.
SQL> select * from patient_diagnosis;

PATIENT_ID DIAGNOSIS_ID DI  DOCTOR_ID BILLING_CODE
---------- ------------ -- ---------- ------------
         1            1 01          1         1003
         1            2 02          1         1003
         1            3 11          1         1003
         2            1 11          1         1005
         2            2 41          2         1005
注意:DIAGNOSIS_CODE 列值显示出来了,因为 ARUP 是表的所有者,ARUP 应该看得到这些值。 现在,以对该表有选择权限的另一名用户身份进行连接,执行相同的查询。
SQL> set null ?
SQL> conn ananda/ananda
SQL> select * from arup.patient_diagnosis;

PATIENT_ID DIAGNOSIS_ID D  DOCTOR_ID BILLING_CODE
---------- ------------ - ---------- ------------
         1            1 ?          1         1003
         1            2 ?          1         1003
         1            3 ?          1         1003
         2            1 ?          1         1005
         2            2 ?          2         1005	 

注意列 DIAGNOSIS_CODE 是如何显示所有空值的。

除了不需要在表上创建视图,不需要创建同义词指向该视图,不需要维护额外的授权之外,该方法是更加优秀的。 如果您需要拥有不同的策略把该值显示给不同的人,您可以很容易地修改策略函数(第 11 行)添加更多的检查。 例如,您的策略可以是:所有用户都可以看到敏感性不强的诊断代码(例如普通感冒)。 因此,您的策略函数和下面的类似,假设一般性感冒的 DIAGNOSIS_CODE 为“01”。

  1  create or replace function pd_pol
  2  (
  3     p_schema        in varchar2,
  4     p_obj           in varchar2
  5  )
6  return varchar2
  7  is
  8     l_ret   varchar2(2000);
9  begin
 10     if (p_schema = USER) then
 11             l_ret := NULL;
 12     else
 13             l_ret := 'diagnosis_code=''01''';
 14     end if;
 15     return l_ret;
16* end;

注意:仅当诊断代码为“01”而不是其它时,我们在第 13 行添加要显示的额外谓词。 现在进行测试。

SQL> conn arup/arup
Connected.
SQL> select * from arup.patient_diagnosis;

PATIENT_ID DIAGNOSIS_ID DI  DOCTOR_ID BILLING_CODE
---------- ------------ -- ---------- ------------
         1            1 01          1         1003
         1            2 02          1         1003
         1            3 11          1         1003
         2            1 11          1         1005
         2            2 41          2         1005

SQL> conn ananda/ananda
Connected.
SQL> select * from arup.patient_diagnosis;

PATIENT_ID DIAGNOSIS_ID DI  DOCTOR_ID BILLING_CODE
---------- ------------ -- ---------- ------------
         1            1 01          1         1003
         1            2 ?           1         1003
         1            3 ?           1         1003
         2            1 ?           1         1005
         2            2 ?           2         1005

注意:诊断代码“01”代表病人 id 1 和诊断 id 1,这是唯一允许的诊断代码;因此显示得很清晰。 其它的显示已经显示为孔,并且得到有效地屏蔽。

提示
如果您想屏蔽敏感列,程序也没有提及到它们,就没有提示。

如果您使用视图方法(这里敏感列只是从该视图中删除),则将会引发一个问题,这里程序使用像 SELECT * FROM TABLE ... 一样的结构。 因为已经没有明确对列进行命名,缺少一列将影响到程序执行。 但是,这不是一个关于修改视图方法(在这里列仍然存在但是为空)的问题。

有一个您应该意识到的很重要的提示。 假如您有一个称为“CONTRACT_AMOUNT”的列;如果数值小于某个特定值(比如 500),该列就显示。如果数值大于 500,该列就显示为空。 该表有三行,这三行所在列的数值分别为 300, 300, 600。 在列屏蔽之前,如果用户提交以下查询

select avg (contract_amount) from contracts;

他将得到 400 (就是 300,300 和 600 的平均值)。 在列屏蔽之后,数值为 $600 的列的值将变为空,因此用户将看到的值分别为 300,300 和空。 现在,输入同样的查询,将会显示 200 (300,300 和空)。 请注意一个重要的区别: 所显示的值为 200;而不是 400

请意识到列屏蔽可能引入的这种重要区别。

操作计划

  1. 在所有敏感的表上列出所有敏感的列。
  2. 确定将要屏蔽的敏感的列。
  3. 确定权限模式。
  4. 如果您使用的是 Oracle 数据库 10g 第 1 版或更高版本,请选择 VPD 方法。
    另外,
    选择基于视图的方法。
  5. 如果您选择 VPD 方法:
    1. 给各个表构建策略函数。
    2. 给各个表构建策略。 这将帮助您在特定的表上对屏蔽进行控制。
  6. 如果您选择基于视图的方法:
    1. 在各个表(表的名字通常为 VW_<table_name>)上创建视图,
    2. 创建指向该视图的同义词(同义词的名称和表的名称相同)。
    3. 在表上撤消给用户授予的权限。
    4. 再次给视图授予权限。
    5. 重新编译所有依赖的无效对象。

(编辑:aniston)

  推荐精品文章

·2024年12月目录 
·2024年11月目录 
·2024年10月目录 
·2024年9月目录 
·2024年8月目录 
·2024年7月目录 
·2024年6月目录 
·2024年5月目录 
·2024年4月目录 
·2024年3月目录 
·2024年2月目录 
·2024年1月目录
·2023年12月目录
·2023年11月目录

  联系方式
TEL:010-82561037
Fax: 010-82561614
QQ: 100164630
Mail:gaojian@comprg.com.cn

  友情链接
 
Copyright 2001-2010, www.comprg.com.cn, All Rights Reserved
京ICP备14022230号-1,电话/传真:010-82561037 82561614 ,Mail:gaojian@comprg.com.cn
地址:北京市海淀区远大路20号宝蓝大厦E座704,邮编:100089