现在位置:首页->学习专题->DB2专题
实现对 DB2 UDB 的低层访问控制
作者: 日期: 2007-12-1 21:08:44 访问次数:出处:
 显示选项:自动滚屏[左键停止]
本文将讲解该主题中的某些问题,并描述如何成功地实现对 DB2 Universal Database(DB2 UDB)的低层访问控制。

  最近,人们对于理解和实现关系数据库中的低层访问控制,表示了浓厚的兴趣,尤其是对列或行级上的访问控制。本文将讲解该主题中的某些问题,并描述如何成功地实现对 DB2 Universal Database(DB2 UDB)的低层访问控制。

  低层访问控制是指,能按行或列来限制数据是否可见或能否被数据库用户修改。过去,在应用程序中通过补充 SQL 语句的谓词,或通过检查返回的数据值以确定行或列是否应该包含在用户可见集合中,来完成该类控制。此方法存在一个较大的不足:它要求应用程序能够阻止用户看到不适当的信息。该方法只在由懂得有关保证数据私密性和完整性的规则并且有望从中受益的机构内部人员开发并验收应用程序的情形下才有效。

  在电子商务的世界里,这些假设都不再适用。数据库中的信息访问正向第三方应用程序以及其 SQL 内容随用户需求和上下文变化的应用程序开放。这意味着,为了确保将规则有效地应用于所有访问数据库的用户和应用程序而不管使用的是什么应用程序,必须将实施低层访问控制的责任推给数据库。这种改变还有利于访问控制策略的集中编码,因为这些策略都是由信息存储的数据库中的信息属主来实现并维护的。

  DB2 UDB 提供了种类繁多的机制,能用以根据用户不同的访问企图,实施相应的访问控制策略。这些机制包括表权限、列权限、视图和触发器。结合用户自定义的访问策略,可通过这些工具在 DB2 UDB 数据库中实现普遍的低层访问控制。

  虽然此论述适用于所有平台(包括 390 和 400),但下面的具体例子是在 DB2 UDB 的 UNIX、Windows 和 OS/2 版上执行的。

  定义访问控制策略

  来看如何实现低层安全的具体例子之前,我们必须回顾访问控制策略中需要定义什么。基本上,我们可以将该问题分为两部分:读访问控制和写访问控制。读访问控制特别与 SELECT 语句相关,而写访问控制则与 INSERT、UPDATE 和 DELETE 语句相关。为了成功地实现和维护一个访问策略,首先要对它进行清晰的定义。对于每行的读/写访问控制策略,需要回答以下问题:

  1. 如何定义一个用户?
    • 它是指一个指定的用户 ID 还是指一类用户?
    • 用什么来标识企图访问各行的用户?例如,可使用用户 ID、部门或城市来标识。
  2. 对于每个用户的访问请求,如何惟一地标识其一个或多个访问级别?
    • 每个用户是否可能有不止一种访问级别?
  3. 对每一行,如何惟一地标识其一个或多个访问级别?
    • 行中哪些属性将用于指明所需的访问级别?例如,可使用供应商、零件号或薪水来指明。
  4. 对一行中每个列,是否有惟一访问要求?如果有,如何惟一地标识它们?
    • 用户能否访问所有的列或某些列,或是否依据用户的访问级别来确定其可访问的列数?如果可访问的列数少于行中总列数,或是随请求者而变化,那么如何确定每个子集的访问级别?
  5. 读和写的行记录集合是否以任何方式相交?
    • 它们是否重叠?一个是否为另一个的子集?
  一旦清晰地定义了这些元素,行和列级上的安全的访问控制策略就可以实现。例如,如果某公司有一张表,包含了所有雇员的信息,那么,该 employee 表的访问控制策略可能就是这个样子:

  行访问策略

公共访问 雇员访问 人力资源访问 管理访问
Read: No rows
Write: No rows
Read: Own row
Write: Own row
Update
Read: All rows
Write: All rows
Update
Insert
Delete
Read: All row
Write: All rows
Update

  列访问策略

列内容 公共访问 雇员访问 人力资源访问 管理访问
Employee Identification Number Read: No
Write: No
Read: Yes
Write: No
Read: Yes
Write: No
Read: Yes
Write: No
Employee User ID Read: No
Write: No
Read: Yes
Write: No
Read: Yes
Write: No
Read: Yes
Write: No
Employee Information Read: No
Write: No
Read: Yes
Write: Update
Read: Yes
Write: Update
Read: Yes
Write: No
Employee Evaluation Read: No
Write: No
Read: No
Write: No
Read: Employee rows only
Write: No
Read: Yes
Write: Update
Department Number Read: No
Write: No
Read: Yes
Write: No
Read: Yes
Write: Update
Read: Yes
Write: No

  该策略为确定允许谁对哪些行或列执行何种操作奠定了基础。要实现该策略,我们还需要一个简洁的定义,以根据将实现该表的数据库的上下文来标识雇员,人力资源部的成员或管理小组的成员。在本例中,我们可以使用以下定义:

  雇员

•将 其数据库用户 ID 出现在该表的 Employee Userid列中的用户定义为公司的雇员。

  人力资源

• d789 部门的雇员为人力资源(Human Resources,HR)部成员;该部门被视作雇员信息表的业务属主。该部门的成员定义为 ‘d789’ 组的仅有成员。

  管理

• d666 部门的雇员为管理(Management)小组的成员。将该部门成员定义为 ‘d666’ 组的仅有成员。

  实现访问控制策略

  一旦创建并验证了访问策略,我们就需要在目标数据库上安全地实现它。正如前面提到的,我们可以使用的工具和方法有很多,而且总是可以通过不同的方法来取得相同的结果。其指导原则就是,要使实现维护和实施起来尽可能简单。易理解的实现同样也易于审计和维护。

  实现读访问策略

  大多数访问策略的读部分最好是通过明智的授权以及使用视图作为到用户的外部接口来实现。第一道防线就是控制何人对主题表有 SELECT 权限。如果用户没有表上的该权限,他/她就不能访问表中的数据。通过最小化该权限的授予,以及将授权的能力只授予自身,您可以最小化访问暴露。

  DB2 对动态的和静态的 SQL 语句均提供支持。静态 SQL 语句存储在系统目录表中,而该系统目录表处于一个称作 包的有组织的集合中。创建包时,DB2 检查执行该创建操作的用户 ID 是否拥有每个静态 SQL 语句所必需的权限。而将该用户 ID 称作 包授权 ID或包的 绑定者(binder)。要创建包,只需将直接访问表的权限显式地授予包的绑定者。一旦创建完成,其他用户就可以执行包中的静态 SQL 语句,只要他们拥有对包本身的 EXECUTE 权限,而无需拥有那些语句所必需的权限。但也请注意要严格控制对表操作的语句,因为它们也被定义为包的一部分。

  对于动态 SQL 语句,DB2 检查企图执行该语句的用户 ID,或检查此 ID 所属的组是否拥有每个动态 SQL 语句所必需的权限。若应用程序被广泛使用,该工作将会十分繁重,因为每个用户要么必须被授予相同的权限,要么必须属于已授权的同一组。既限制对表的访问又不失动态 SQL 语句提供的灵活性的方法就是,在创建由应用程序使用的包时,使用 DYNAMICRULES(BIND) 选项。该选项表示将包授权 ID 用作包中所执行的动态 SQL 的授权 ID。这样做能简化事情是因为,与静态 SQL 语句采用的方式一样,只需要用创建包所使用的授权 ID 来获得表上的授权。

  将视图作为首要工具来实现读访问策略是有利的,因为可以构造视图来隐藏行和/或列的存在,以及修改列的内容。视图的存在还允许通过它来解决主题表上访问权限的焦点问题;而用户只需被授予视图上的而非主题表本身上的 SELECT 权限。

  要进一步阐述前面给定的雇员信息表上的访问策略示例,我们可以先定义所需的表和数据,如下列 SQL 语句所示。为了使示例保持清晰,我们简化了该场景。

— 创建 department 表
create table bigco.department   (department_id                 char(4) not null primary key,
  department_info    varchar(255));
— 创建 employee 信息表
create table bigco.employee    (employee_id          int not null primary key,
  employee_userid    char(30) not null unique,
  employee_info   varchar(255),
  employee_evaluation   char(4) default ‘ ‘,
  department_id   char(4) not null
      references bigco.department);
— 插入部门信息
insert into bigco.department values (‘d111’, ‘Marketing’), (‘d222’,’Inventory Control’),
  (‘d333’,’Accounting’), (‘d789’,’Human Resources’),
  (‘d666’,’Management’);
— 插入雇员信息
insert into bigco.employee values (1, ‘HUGO’,’some fascinating tidbits’,’A111’,’d666’),
  (2, ‘MARY’,’some fascinating tidbits’,’B212’,’d789’),
  (3, ‘FRUITFLY’,’some fascinating tidbits’,’FFFF’,’d111’),
  (4, ‘PBIRD’,’some fascinating tidbits’,’B114’,’d222’),
  (86,’MAX’,’some fascinating tidbits’,’A32A’,’d333’);

  一旦定义了这些基本表,通过使用视图和授予 SELECT 权限,我们就可以实现之前为雇员信息表定义的读访问策略了。本例中,我们可以使用两个视图定义:一个允许雇员查看他们自己的行,另一个则允许管理部门和人力资源(HR)部门的成员查看 employee 表中的全部行。

— 创建这样的视图,以允许雇员访问 employee 表中自己的行和某些列
create view bigco.employee_access
  (Employee_ID, User_ID, Employee_Information, Department_ID) as
(select employee_id, employee_userid, employee_info, department_id
from employee
where employee_userid = USER);
— 允许所有雇员读访问 employee 视图
grant select on bigco.employee_access to public;
— 创建这样的视图,以允许 HR 部门和管理部门访问所有的行
create view bigco.mgmt_access
  (Employee_ID, User_ID, Employee_Information, Department_ID, Employee_Evaluation) as
(select employee_id, employee_userid, employee_info, department_id,
— 如果是管理部门中的雇员,那么只允许
  — 管理部门中的用户看到 Evaluation 表
    case when (department_id = ‘d666’)
      then case (select department_id
          from bigco.employee as x
where x.employee_userid = USER)
        when ‘d666’ then employee_evaluation
else ‘N/A’
      end      
        else employee_evaluation
    end        
  from bigco.employee);
— 允许管理部门和 HR 部门的所有成员读访问 management 视图
grant select on bigco.mgmt_access to group d666, group d789;

  如下面的例子所示,基于使用不同的视图及其用户信息,我们将得到不同的结果。请注意 mgmt_access视图没有隐藏 employee_evaluation部门的成员查看一个管理人员的行时,该视图就隐藏了,或者说屏蔽了该列的值。我们还确保没有人可以越过各个视图上的授权设置:没有人可以对基本表执行 select 访问;只有 ‘d789’ 和 ‘d666’ 组的成员可以对 mgmt_access视图执行 select 访问,但所有人都可以访问 employee_access视图。本例假设使用动态 SQL 来访问多个表,所以与组授权相关。在静态 SQL 授权模式中,不能对任何组授权,只对指定的用于绑定包含了 SQL 的包的授权 ID 授权。通过对每个包使用一个不同的授权 ID,可以取得类似于静态 SQL 的权限判别。例如,一个包含了静态 SQL 的包可被所有雇员使用,并且可将对 employee_access视图的访问限于拥有其 SELECT 权限的某个授权 ID,那么,该包上的 EXECUTE 权限就可授予 PUBLIC。通过该方法,没有雇员可以访问表和视图,他们只能通过包中的静态 SQL 来获取信息。

— 由非 HR 部门的雇员(PBIRD)对 employee 表所作的选择(无访问权限)
select * from bigco.employee;
SQL0551N “PBIRD” does not have the privilege to perform operation “SELECT”
on object “BIGCO.EMPLOYEE”. SQLSTATE=42501.

— 由管理部门的雇员(HUGO)对 employee 表所作的选择(无访问权限)
select * from bigco.employee;
SQL0551N “HUGO” does not have the privilege to perform operation “SELECT”
on object “BIGCO.EMPLOYEE”. SQLSTATE=42501.

— 由非 HR 部门的雇员(PBIRD)对 employee_access 视图所作的选择
select employee_id, user_id, department_id from bigco.employee_access;
EMPLOYEE_ID        USER_ID                                                               DEPARTMENT_ID
——————————- ——————————————— ————————————-
                                     4 PBIRD                                                                         d222
1 record(s) selected.

— 由管理部门的雇员(HUGO)对 employee_access 视图所作的选择
select employee_id, user_id, department_id from bigco.employee_access;
EMPLOYEE_ID        USER_ID                                                               DEPARTMENT_ID
——————————- ——————————————— ————————————-
                                     1 HUGO                                                                         d666
1 record(s) selected.

— 由非 HR 部门的雇员(PBIRD)对 mgmt_access 视图所作的选择(无访问权限)
select employee_id, user_id, employee_evaluation from bigco.mgmt_access;
SQL0551N “PBIRD” does not have the privilege to perform operation “SELECT”
on object “BIGCO.MGMT_ACCESS”. SQLSTATE=42501.

— 由 HR 部门的雇员(MARY)对 mgmt_access 视图所作的选择(隐藏了 management evaluations)
select employee_id, user_id, employee_evaluation from bigco.mgmt_access;

EMPLOYEE_ID        USER_ID                                                      EMPLOYEE EVALUATION
——————————- ——————————————— ————————————-
                                     1 HUGO                                                                        N/A
                                     2 MARY                                                                        B212
                                     3 FRUITFLY                                                                 FFFF
                                     4 PBIRD                                                                        B114
                                     86 MAX                                                                        A32A
5 record(s) selected.

— 由管理部门对 mgmt_access 视图所作的选择(显示所有 evaluations)
select employee_id, user_id, employee_evaluation from bigco.mgmt_access;
select employee_id, user_id, employee_evaluation from bigco.mgmt_access;

EMPLOYEE_ID        USER_ID                                                        EMPLOYEE EVALUATION
——————————- ——————————————— ————————————-
                                     1 HUGO                                                                        A111
                                     2 MARY                                                                        B212
                                     3 FRUITFLY                                                                 FFFF
                                     4 PBIRD                                                                        B114
                                     86 MAX                                                                        A32A
5 record(s) selected.

实现写访问策略

  与读访问一样,对授予主题表上写权限(即 INSERT、UPDATE 或 DELETE 权限)的控制是最基本的防御。如果用户没有权限,就不能执行操作。当然,如果一个表需要修改,那么假设您可以避免授权该表的写访问是不现实的。如果您必须授予用户对表的写权限,那最好尽可能最小化授权范围。例如,授予 UPDATE 权限时,如果只需更新所有列的一个子集,那么就只授予所必需的列上的权限。又与读权限一样,您也可以选择使用静态 SQL 或动态 SQL 授权模式,DB2 提供这些模式来控制谁在何种上下文中拥有何种权限。

  无论何时,只要条件允许,我们同样推荐以视图作为首要的写访问点。通过向用户授予视图上的写权限,您可以避免授予主题表上的直接权限。无论是从权限还是从表的内容和结构出发,控制对主题表的直接访问时,都允许从用户角度来维护一个一致的外部访问点。视图定义中 WITH CHECK OPTION 从句的使用,确保了任何企图通过视图进行的写访问都要满足视图自身的条件。视图定义中的 WITH CHECK OPTION 确保企图在视图上进行的写访问与通过视图所读取的行在逻辑上要保持一致。也就是说,正在修改的行对于通过此视图定义提出修改请求的用户必须是可见的。该条件适用于所有的 INSERT、UPDATE 和 DELETE 操作。当通过读和写访问策略为某个用户定义的行集合相同时,该条件就十分强大。因为那个用户仅通过视图定义以及视图上的授权就可以执行所有访问,而无须附加任何实施机制。在前面讨论如何实现读访问控制时,我们给出了视图定义。下面的例子展示了如何修改此定义,使其包括 WITH CHECK OPTION 从句。

— 创建这样的视图,以允许雇员访问 employee 表中自己的行和某些列
create view bigco.employee_access
  (Employee_ID, User_ID, Employee_Information, Department_ID) as
(select employee_id, employee_userid, employee_info, department_id
from employee
where employee_userid = USER);
with check option;
— 创建这样的视图,以允许 HR 部门和管理部门访问所有的行
create view bigco.mgmt_access
  (Employee_ID, User_ID, Employee_Information, Department_ID, Employee_Evaluation) as
(select employee_id, employee_userid, employee_info, department_id,
    case when (department_id = ‘d666’)
      then case (select department_id
          from bigco.employee as x
where x.employee_userid = USER)
        when ‘d666’ then employee_evaluation
else ‘N/A’
      end      
        else employee_evaluation
    end        
  from bigco.employee);
with check option;

  有了这些新修改的视图定义,我们就可以授予所需的权限,以实现前面定义的访问控制策略中的写部分(如下所示)。

— 允许 employee_access 视图上的所有人更新 employee_information
grant update(employee_information) on bigco.employee_access to public;

— 允许 HR 部门在 mgmt_access 视图上更新 employee_information
grant update(department_id, employee_information) on bigco.mgmt_access to group d789;

— 允许 HR 部门在 mgmt_access 视图上执行删除
grant delete on bigco.mgmt_access to group d789;

  视图定义和权限相结合将有效地控制不同用户访问雇员信息的行为。下面的例子显示了通过 employee_access和 mgmt_access这两个视图进行的不同数据修改所得的结果。请注意因为还没有人获得基本表上的授权,所以任何部门的任何雇员企图访问这些表都将失败。

— employee_access 例子

— 一般雇员(PBIRD)企图更新 employee_information
update bigco.employee_access set employee_information = ‘A different tidbit’;
DB20000I The SQL command completed successfully.
— 注意只更新了 PBIRD employee_information

— 一般雇员(PBIRD)企图更新 MARY 的 employee_information
update bigco.employee_access set employee_information = ‘A different tidbit too’
         where user_id = ‘MARY’;
SQL0100W No row was found for FETCH, UPDATE or DELETE; or the result of a
query is an empty table. SQLSTATE=02000

— 一般雇员(PBIRD)企图更新 employee_id
update bigco.employee_access set employee_id = 77;
SQL0551N “PBIRD” does not have the privilege to perform operation “UPDATE”
on object “BIGCO.EMPLOYEE_ACCESS”. SQLSTATE=42501

— HR 部门的雇员(MARY)企图更新 MAX 的 employee_information
update bigco.employee_access set employee_information = ‘An exciting tidbit’ where user_id = ‘MAX’;
SQL0100W No row was found for FETCH, UPDATE or DELETE; or the result of a
query is an empty table. SQLSTATE=02000

— HR 部门的雇员(MARY)企图插入一个新雇员
insert into bigco.employee_access values (99, ‘BARBARA’, ‘some fascinating tidbits’, ‘d111’);
SQL0551N “MARY” does not have the privilege to perform operation “INSERT”
on object “BIGCO.EMPLOYEE_ACCESS”. SQLSTATE=42501

— HR 部门的雇员(MARY)企图删除一个雇员
delete from bigco.employee_access where user_id = ‘MAX’;
SQL0551N “MARY” does not have the privilege to perform operation “DELETE”
on object “BIGCO.EMPLOYEE_ACCESS”. SQLSTATE=42501

  此时,我们已经实现了之前定义的几乎所有的访问控制策略。剩下的两条是使 HR 部门的雇员能向 employee表插入新的雇员记录,以及使管理部门的成员能更新 employee表的 employee_evaluation列。根据 mgmt_access视图中的定义,其中的 employee_evaluation列不能被更新,因为该列是通过 case 表达式的结果构造的。本例中,我们需要实现另一种方法来提供并控制指定的访问。

  除了需要更新视图中不可更新的列之外,还有其他几种情况也需要不同于传统的视图方法来提供写访问控制。这些情况包括:

• 只读视图(视图定义不允许通过该视图进行插入或修改操作)。
• 用户可读取的行集合与其可修改的集合不相同。

  这些情况需要用户采用与读访问不同的方法来修改数据。虽然通过用不同的定义为插入和更新操作创建新视图,仍然可以坚持限制表上的直接授权的原则,但用户只能用新视图执行写访问,原因是其定义不可能同时支持读访问控制。对于此类视图,只能授予用户视图上的写权限,而不能授予读权限。在有限的一些例子中,某些管理员或许喜欢采用更简洁的方法,就是向用户提供直接对表进行 INSERT、UPDATE 或 DELETE 操作的权限。不管采用何种方法授予写权限,都需要在目标表本身上实施写访问控制策略。这些情况下,在表上创建合适的 INSERT、UPDATE 或 DELETE 触发器可以为实施必需的写访问策略提供条件。触发器中使用的基本机制与视图定义中使用的相似:触发器定义中的 WHEN 从句用于判断激活该触发器的操作是否违反了访问策略,或者,至少用于判断在允许企图进行的操作继续之前是否还需对其进一步分析。触发器的主体将最终判断是否违反了访问策略,若有必要,它还将采取行动阻止访问操作。为了在将来修改时易于维护,触发器定义应该尽可能清楚且简单,并包含适当的注释。请注意这些策略实施触发器将十分有效,并能保护主题表免受所有企图进行的写访问的损害,无论该访问是直接对表进行的还是通过视图进行的。

  在决定如何通过触发器实现访问策略时,有许多可用的选项。首先,有必要确定在企图进行不正确或被限制的访问的时候,采用何种方法应对。是应该返回一条错误消息,还是应该使此受限的访问无效并允许其他处理继续进行?通过使用 SIGNAL SQLSTATE 语句,可从触发器中返回错误消息。触发器中的出错信号将回滚违反访问策略的语句,且该语句所做的任何修改都将从数据库中清除。某些情况下,修改了许多行,我们或许期望仅仅清除那些导致错误情况的行,并允许成功地完成语句的处理。为了允许语句继续执行而屏蔽掉错误行所需的技术取决于触发器的类型。下文讨论了对于每种触发器可能的无效操作。然而,一般说来,应该通过向用户发送错误消息来处理访问违规,而非仅使访问结果无效却无可见的出错提示。在处理访问企图时,触发器比视图要灵活得多。因此,在决定如何处理这些触发器中所发现的失败访问时,应该考虑是否记录此违法操作,用于审计以及将来可能继续的活动中。

  要实现针对不能通过视图中的 WITH CHECK OPTION 从句实现的更新操作的访问控制,我们推荐在主题表上定义一个 NO CASCADE BEFORE 类型的行级别的 UPDATE 触发器。在 UPDATE 语句执行的操作应用于每一行之前,这种触发器可对这些行逐行判断。通过适当调整 update 触发器中的判断内容,能使其只对表中指定列的更新敏感。这样做是为了尽可能最小化进行判断所带来的开销。在这种触发器中,为了使违规的 UPDATE 访问无效

⊕相关文章
  • ·DB2数据库安全涉及的问题
  • ·DB2 数据库身份验证基础
  • ·关于DB2 数据库授权的研究
  • ·提高DB2 Web程序性能5条规则
  • ·DB2第四类java驱动
  • ·理解 DB2 UDB JDBC 通用驱动程序