背景


根据控制对象的粗细程度,访问控制可分为粗粒度和细粒度两种 通常把规定访问整个数据库表或由基本表导出的视图的某个层称为粗粒度的访问控制,而细粒度控制则是把安全控制细化到数据库的行级或列级。

我们给银行上了一套系统,银行的政策允许所有财务经理可以访问所有账户持有人的信息,但在最近,对该政策做了改变只允许财务经理访问特定的客户集,那么为了使应用程序符合新的政策,我们必须对应用程序进行修改,有三种选择

1.         修改应用程序代码,使所有SQL语句都包含一个WHERE子句。但如果将来政策又有变化,则必须再一次修改代码,所以从长远考虑这不是一个好方法

2.         保持应用程序不动,用判定词创建表的视图,并用与表名一样的名字为这些视图创建同义词 。从应用程序不变更和安全性的角度来看这种方法比较好,但可能难于管理,因为有大量潜在的视图需要跟踪和管理

3.         保持应用程序不动,使用Truman模型实现。

 


文档术语


 

 

简称

英文

说明

RLS

Row Level Security

行级别安全性

VPD

Virtual Private database

虚拟专有数据库

同义词

synonym

别名的意思,类似视图。

就是一种映射关系

 

 

 

 

 

 

 


Truman模型


U.C. Berkeley 的 Shariq Rizvi 和其他人提出了 Truman 模型,该模型基于数据库级别修改查询。Truman 模型的想法是为每个用户提供数据库的个人视图。为实现此目的,需要对用户的查询进行修改以确保用户不能查看允许之外的内容。

         Truman 模型:用户向数据库提交SQL语句,修改器拦截用户提交的语句,通过一定的策略修改语句后再执行。如下图:

    

 

在Truman 模型下,相当于每个用户都拥有自己的私有数据库,用户在该数据库中进行数据管理(如查询,添加和修改数据)。

 

Truman 模型有时也称为细粒度访问控制 (FGAC) 或行级安全 (RLS)。(该模型名称的灵感源自于 1998 年的电影 The Truman Show 中 Truman Burbank 角色所处的人工世界)。

该模型的优点包括:单点授权实施、可以拥有动态的集合、最终用户查询功能以及高效的数据处理(这是空间数据一个主要方面)。

Truman模型的实现有:

l  Oracle的VPD。

l  Research的RLS。

l  SQL Server的RLS。


Oracle的RLS


Oracle一直都提供授权(或拒绝)用户访问数据库对象的能力,但这些对象粒度只到表或视图这一级别。Oracle8i的企业版中引入行级安全性,提供行级粒度的访问控制。Oracle10G中引入列级别安全性,提供列级粒度的访问控制。

行级安全性不是向对表有任何访问权限的用户打开整张表,而是将访问限定到表中特定的行。每个用户只能看到那些该用户被授权可以查看的数据。

VPD包含两个要素:策略(Policy)策略函数(Policy Function)


VPD的策略


策略(Policy)用于管理(如添加,删除,修改)对哪些对象(表或视图)执行RLS控制。

VPD包含的策略非常多,如添加策略,删除策略,刷新策略,启用策略,创建策略组,创建策略上下文等,更多策略及其详细内容参见ORACLE的DBMS_RLS本文只详细讨论添加策略和删除策略。

添加策略

 

-- Apply the policy function to the table.

BEGIN

  DBMS_RLS.ADD_POLICY (object_schema     => 'scott',

                       object_name       => 'emp',

                       policy_name       => 'sp_job',

                       function_schema   => 'scott',

                       policy_function   => 'pf_job',

                       sec_relevant_cols => 'sal,comm');

END;

添加策略的所有属性如下:

l  Object_Name:表名、视图名或同义词

l  Object_Schema:用户名

l  Policy_name:策略名称

l  Policy_function:需要使用的策略函数

l  Function_schema:策略函数所属用户

l  Statement_type:应用策略的DML,可以是select,insert,update,delete的任意组合

l  Update_check:在insert和update的时候是否检查。

l  Enable:是否启用策略

l  Static_policy: 默认为false,设置为true时,该策略为任何访问该对象的人产生相同的谓词字符串。

l  Policy_type: 默认为STATIC,允许的值是STATIC、SHARED_STATIC、CONTEXT_SENSITIVE、SHARED_CONTEXT_SENSITIVE和DYNAMIC。

l  Long_predicate:该参数默认为FALSE。如果它为TRUE,谓词字符串最多可为32K字节长。否则,限制为4000字节

l  Sec_relevent_col:10G新增,设置受保护的列,被设置的列的数据将不会显示,只能应用与表和视图,使用逗号或空格作为分隔符。假如DML语句中不含有设置的列,则忽略此策略。

l  sec_relevant_cols_opt:10G新增,允许在列级别VPD过滤查询中的行仍然出现在结果集中,敏感列返回NULL值。指定DBMS_RLS.ALL_ROWS显示所有列。

 

删除策略

 

-- Remove the policy function from the table.
BEGIN
  DBMS_RLS.DROP_POLICY (object_schema     => 'scott',//用户名
                        object_name       => 'emp',//表名,视图名
                        policy_name       => 'sp_job');//策略名
END;
/


策略类型

正确的使用策略类型能提高VPD的效率,通过缓存策略函数的输出,使得随后的查询语句,不再执行策略函数,DBMS_RLS.ADD_POLICY存储过程的策略类型参数可以设置5种策略类型中的一种。

Ø  静态类型:缓存策略函数的返回值,可以被个别对象重复利用,所以策略函数的返回值必须静态。

Ø  共享静态类型,同静态类型一样,但是生成的谓语能够被应用与多个对象。

Ø  敏感上下文类型:当策略基于本地应用上下文的时候使用,策略函数的结果被缓存和重复使用,只有当应用上下文改变的时候策略函数才会再一次执行。

Ø  共享敏感上下文:同敏感上下文类型一样,但是生成的谓语能够应用与多个对象。

Ø  动态类型:策略函数在每此执行SQL语句的时候都被执行。



VPD的策略函数


策略函数(Policy Function):用于设置判断条件,以过滤没有权限显示的行。

 

函数包定义
CREATE OR REPLACE PACKAGE exp_security AS
FUNCTION client_id_security(owner VARCHAR2, objname VARCHAR2)
   RETURN VARCHAR2;
END exp_security;
 
该函数的主体如下所示: 
CREATE OR REPLACE PACKAGE BODY exp_security IS
FUNCTION client_id_security(owner VARCHAR2, objname VARCHAR2) RETURN VARCHAR2 IS predicate VARCHAR2(2000);
  BEGIN
    predicate := 'CLIENT_ID = sys_context(''THE_CTX'',''THE_CLIENT_ID'')';
    RETURN predicate;
  END client_id_security;
END;

 


Research的RLS


Microsoft Research 最新发布的一篇文章讨论了 Truman 模型,本文提出了一种分配谓词授权的新方法。以下是一个授权查询示例:

 

GRANT SELECT employees // 策略定义
WHERE emp_id = user_id()//授权模型
TO PUBLIC

因此,谓词将纳入到普通的授权语句中。这与 Oracle VPD的实现相反,Oracle VPD 的实现是将策略定义(policy)与 SQL 授权模型(policy function)相分离。

 


SQLServer的RLS


         SQL Server中的行级安全性解决方案具有一定的侵入性。它需要为每一个数据表添加一个参数列,用于区分当前行的数据,属于哪一个用户或者角色。然后创建参数化的视图或者存储过程,传入适当的值。

具体实现步骤

1.         创建表,添加用于存储用户名的附加列。如 Asset资产表,添加user_name列。

2.         基于用户名列创建一个具有 WHERE 子句的视图。

 

Create view V$ASSET as select * from  Asset  where user_name =user_name ();

3.   基于视图创建用于查询,插入、更新和删除数据的存储过程。

4.   对于插入数据的存储过程,使用user_name ()函数捕获用户名并将该值插入 UserName 列。

5.   拒绝 public 角色对表和视图的所有权限。

6.         为数据库角色授予对存储过程的 EXECUTE 权限。用户只能通过提供的存储过程访问数据。