常规的权限控制,是通过授予和拒绝(Grant/Deny)命令,控制用户对数据库对象(数据表或视图)的访问权限,用户访问的粒度是对象的全部数据行,这意味着,用户要么有权限访问该对象,要么没有权限访问该对象,无法实现使特定的数据行只允许特定的用户访问,但是,行级安全(Row-Level Security,简称 RLS)可以实现该该需求。

RLS根据用户的安全上下文控制用户可以访问的数据行。RLS主要由两部分构成:安全策略(Security Policy)和安全断言(Security Predicate),一个安全策略可以添加多个安全断言。

  • 如果安全策略(Security Policy)被禁用,那么用户总是访问所有数据行,跟数据表上不关联任何安全策略一样。
  • 如果安全策略(Security Policy)被启用,那么用户在数据行级别上控制用户的访问,粒度是数据行,控制用户只能访问数据表的特定数据行。

RLS是基于安全断言(Security Predicate)来实现行级的访问控制,断言(Predicate )是逻辑表达式,返回的结果是布尔(boolean)值:true 或false。Security Predicate是由内联表值函数实现的,该函数称作断言函数(Predicate Function)。当断言函数返回的数据行不是空时,安全断言的结果是True;当断言函数不返回数据行时,安全断言的结果是False。

在目标表上实现RLS,控制用户访问数据行的权限,通常需要显式定义3个组件:

  • 断言函数(Predicate Function):是内联表值函数,用于执行安全断言,Security Policy调用该函数过滤数据行或阻塞写操作;
  • 安全策略(Security Policy):将目标数据表和断言函数绑定,并设置安全断言的类型;
  • 权限配置表:如果需要对用户访问目标数据表的权限进行动态控制,还需要定义权限配置表。权限配置表通常由两列:User Name 和 Rowset,用于表示用户有权限访问的行集。

一,定义安全断言(Security Predicate)

如果在数据表上启用RLS,那么一个用户访问数据行的权限受到安全断言(Security Predicate)的限制,Security Predicate 是在内联表值函数中定义的逻辑表达式,Security Policy调用内联表值函数,返回Security Predicate 的结果。在用户访问行级别数据时,SQL Server自动执行预定义的安全策略(Security Policy),仅当Security Predicate返回逻辑True时,才允许用户访问指定的数据行;如果Security Predicate 返回逻辑False,那么不允许用户访问数据。如果在一个数据表上创建了Security Policy,但是,安全策略(Security Policy)被禁用,那么,Security Predicate将不会过滤或阻塞任何数据行,不执行任何的Filter 或 Block操作,用户能够访问所有的数据行。

下面的示例代码定义了断言函数(Predicate Function),该表达式根据用户名作为断言控制用户对数据行的访问:

CREATE FUNCTION rls.fn_securitypredicate
(@SalesRep AS sysname)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN SELECT 1 AS fn_securitypredicate_result
WHERE @SalesRep = USER_NAME() OR USER_NAME() = 'Manager';

通常情况下,实现RLS的目的是为了根据权限配置表对用户的访问目标表的权限进行动态控制。假定权限配置表只有两列:UserName和Rowset,在定义断言函数时,需要同时传递用户名称和RowSet参数。

create function rls.fn_SecurityPredicate_ByUserName
(@UserName as sysname,@Rowset as int)
returns table
with schemabinding
as
return
(
select UserName
from rls.UserSecurityConfig
where UserName=substring(@UserName, charindex('\',@UserName)+1,len(@UserName))
and RowSet=@Rowset
)
go

二,过滤断言和阻塞断言(Filter 和 Block)

在Security Policy中,RLS支持两种类型的安全断言(Security Predicates):

  • Filter Predicate:当用户从目标表读取数据行时,Filter Predicate透明地过滤数据行,用户只能读取有权限访问的数据行;如果所有的数据行都被过滤掉,那么返回空集给用户;
  • Block Predicate:当违反断言时,阻塞写操作事务的提交,回滚写操作事务;

1,过滤断言(Filter Predicate)

当从目标标中读取数据时,读操作受到Filter Predicate的影响,读取数据的操作包括:select,delete和update,用户不能查询,删除和更新被过滤的数据行。

过滤断言(Filter Predicate)定义的安全策略,使得用户在Base Table上执行select,update和delete命令时,不会意识到Filter操作的存在,Security Policy透明地过滤数据行,但是用户能够插入任何数据,不管数据是否被过滤掉,用户也可以把数据更新为被过滤的数据。也就是说,用户更新的数据可能会违反安全断言。

2,阻塞断言(Block Predicate)

阻塞断言(Block Predicate)阻塞所有违反安全断言的写操作,有四种阻塞操作:

  • After Insert 断言:阻止用户插入违反断言的字段值,就是说,用户插入的数据必须满足断言;
  • After Update 断言:阻止用户将数据更新为违反断言的字段值,就是说,数据被更新后,其值必须满足断言;
  • Before Update 断言:只允许用户更新符合断言的数据行,就是说,在Update之前,对于符合断言的数据行,用户能够更新为任意值;
  • Before Delete 断言:只允许用户删除符合断言的数据行,就是说,在Delete之前,对于符合断言的数据行,用户能够删除;

阻塞操作有分为After 和Before选项:

  • After 指定:在执行Insert 或 Update操作之后,计算断言的逻辑结果;如果逻辑结果为false,那么回滚Insert 或 Update操作;
  • Before 指定:在执行Update 或Delete 操作之前,计算断言的逻辑结果,用户只能Update或Delete符合断言的数据;
  • 如果没有指定,那么默认会指定所有四种阻塞操作。

3,过滤断言和阻塞断言的SCHEMABINDING选项

在定义断言函数时,可能需要与表、视图进行连接,或者调用函数。当创建Security Policy指定SCHEMABINDING = ON选项,不会对断言函数内部调用的表或函数做额外的权限检查。如果指定的SCHEMABINDING = OFF选项,那么用户需要被授予断言函数内部调用的表或函数上的SELECT 或EXECUTE权限。也就是说,如果使用SCHEMABINDING = OFF选项创建安全策略,那么在查询目标表之前之前,必须对断言函数、以及断言函数调用的表、视图或函数具有SELECT 或EXECUTE权限。如果使用SCHEMABINDING = ON选项创建安全策略,当用户查询目标表时,将绕过这些权限检查。

4,安全策略是安全断言的容器

一个安全策略可以定义多个安全断言,对多个目标表进行RLS权限控制。

三,创建RLS的示例

使用RLS控制用户只能访问指定的数据,第一步是创建断言函数,第二步是创建安全策略,这两个对象都有架构。强烈推荐创建一个单独的Schema,用于RLS对象(Predicate Function和 Security Policy),本例中创建rls架构。

create schema rls
authorization dbo;

1,创建断言函数

创建内联表值函数,用于过滤数据行,返回安全断言的结果:

--create function
CREATE FUNCTION rls.fn_securitypredicate
(@SalesRep AS sysname)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN SELECT 1 AS fn_securitypredicate_result
WHERE @SalesRep = USER_NAME() OR USER_NAME() = 'Manager';

2,创建和启动安全策略(Security Policy)

创建Security Policy,把目标表和Security Predicate 绑定,添加Filter Predicate,并向断言函数传递目标表 dbo.Sales的字段SalesRep字段作为参数值:

CREATE SECURITY POLICY rls.SalesFilter
ADD FILTER PREDICATE rls.fn_securitypredicate(SalesRep)
ON dbo.Sales
WITH (STATE = ON, SCHEMABINDING=ON);

3,测试安全策略(Security Policy)

由于断言函数中使用User_Name来获取用户的名称,因此,可以使用EXECUTE AS命令来模拟用户的权限:

EXECUTE AS USER = 'Sales1';
SELECT USER_NAME() as UserName,*
FROM dbo.Sales;
REVERT; EXECUTE AS USER = 'Manager';
SELECT USER_NAME() as UserName,*
FROM dbo.Sales;
REVERT;

如果要避免权限模拟对数据安全带来的隐患,建议在断言函数中使用原始Login:

ORIGINAL_LOGIN( ) 

四,维护安全策略(Security Policy)

安全策略(Security Policy)适用于所有的用户,包括最高权限角色 sysadmin 和 db_owner 的成员,以及dbo用户,虽然这些成员拥有很高的权限,能够更改Security Policy的定义,甚至删除Security Policy,但是,在访问数据行时,仍然会受到Security Policy的影响,访问的数据是Filter 或Block的结果。一个User要想访问所有的数据行,必须在Predicate Function中显式定义。一般情况下,会设置一个管理RLS的Manager用户,用于维护Security Predicate控制的数据,必要时对数据处理进行故障排除。如果安全策略(Security Policy)被禁用,那么,用户在访问数据表时,不会Filter或Block任何数据行,看到的数据表的全部数据行。

1,启用或禁用安全策略(Security Policy)

--diable
ALTER SECURITY POLICY rls.SalesFilter
WITH (STATE = OFF);
--enable
ALTER SECURITY POLICY rls.SalesFilter
WITH (STATE = ON);

2,更新安全策略

用户可以把安全策略应用到多个表上:

ALTER SECURITY POLICY rls.SalesFilter
ADD FILTER PREDICATE rls.fn_securitypredicate(SalesRep)
ON dbo.FactSales;

3,查看系统中的安全策略和断言

select p.object_id as security_policy_id
,s.name as security_policy_name
,s.is_enabled as security_policy_state
,s.is_schema_bound
,p.security_predicate_id
,p.target_object_id
,schema_name(o.schema_id)+'.'+object_name(p.target_object_id) as target_object_name
,p.predicate_definition
,p.predicate_type_desc
,p.operation_desc
from sys.security_predicates p
inner join sys.security_policies s
on p.object_id=s.object_id
inner join sys.objects o
on p.target_object_id=o.object_id

五,RLS对查询性能的影响

RLS会影响查询的性能,RLS 过滤断言在功能上等价于在查询的(Where)上追加一个条件。在创建安全策略时,应该使断言函数内的查询足够简单。

参考文档:

CREATE SECURITY POLICY (Transact-SQL)

Row-Level Security

行级安全(Row-Level Security)的更多相关文章

  1. Security Policy:行级安全(Row-Level Security)

    行级安全RLS(Row-Level Security)是在数据行级别上控制用户的访问,控制用户只能访问数据库表的特定数据行.断言是逻辑表达式,在SQL Server 2016中,RLS是基于安全断言( ...

  2. Implementing SQL Server Row and Cell Level Security

    Problem I have SQL Server databases with top secret, secret and unclassified data.  How can we estab ...

  3. 行级安全(Row

    通过授予和拒绝(Grant/Deny)命令控制用户的权限,只能控制用户对数据库对象的访问权限,这意味着,用户访问的粒度是对象整体,可以是一个数据表,或视图等,用户要么能够访问数据库对象,要么没有权限访 ...

  4. 【数据库】数据库的锁机制,MySQL中的行级锁,表级锁,页级锁

    转载:http://www.hollischuang.com/archives/914 数据库的读现象浅析中介绍过,在并发访问情况下,可能会出现脏读.不可重复读和幻读等读现象,为了应对这些问题,主流数 ...

  5. PowerBI开发 第十五篇:Power BI的行级安全

    Power BI支持行级安全(Row-Level Security,RLS)的权限控制,用于限制用户对Dashboard.报表和DataSet的访问.用户浏览的报表是相同的,但是看到的数据却是不同的. ...

  6. 第十篇 SQL Server安全行级安全

    本篇文章是SQL Server安全系列的第十篇,详细内容请参考原文. 不像一些其他industrial-strength数据库服务,SQL Server缺乏一个内置保护个别数据记录的机制,称为行级安全 ...

  7. 【译】第十篇 SQL Server安全行级安全

    本篇文章是SQL Server安全系列的第十篇,详细内容请参考原文. 不像一些其他industrial-strength数据库服务,SQL Server缺乏一个内置保护个别数据记录的机制,称为行级安全 ...

  8. 通用高效的数据修复方法:Row level repair

    导读:随着大数据的进一步发展,NoSQL 数据库系统迅速发展并得到了广泛的应用.其中,Apache Cassandra 是最广泛使用的数据库之一.对于 Cassandra 的优化是大家研究的热点,而 ...

  9. MySQL行级锁,表级锁,页级锁详解

    页级:引擎 BDB. 表级:引擎 MyISAM , 理解为锁住整个表,可以同时读,写不行 行级:引擎 INNODB , 单独的一行记录加锁 表级,直接锁定整张表,在你锁定期间,其它进程无法对该表进行写 ...

随机推荐

  1. Linux 同步时间 设置时区

    简化版 同步时间 #直接用域名同步中国上海时间 ntpdate -u ntp.api.bz # hwclock --hctosys 或者 # clock --hctosys hc代表硬件时间,sys代 ...

  2. continue break exit用法说明

    1,continue用法 2,break用法 3,sys.exit用法 1,continue用法(跳出本次循环,继续下次循环) for i in xrange(10): if i == 8: cont ...

  3. 【EJB学习笔记】——EJB开发环境搭建(Eclipse集成JBoss)

    之前一直用的EJB开发环境是他们搭建好的,直接拿来用,不过还是感觉老吃别人嚼好的不太好吃,所以自己动手来玩一玩. EJB开发依赖的最基本的环境:JDK.Eclipse.JBoss,这里简单介绍一下最基 ...

  4. jQuery插件实例四:手风琴效果[无动画版]

    手风琴效果就是内容的折叠与打开,在这个插件中,使用了三种数据来源:1.直接写在DOM结构中:2.将数据写在配置项中:3.从Ajax()中获取数据.在这一版中,各项的切换没有添加动画效果,在下一版中会是 ...

  5. 了解注解及java提供的几个基本注解

    先通过@SuppreessWarnings的应用让大家直观地了解注解: 通过System.runFinalizersOnExit(true);的编译器警告引出           @SuppressW ...

  6. 用python实现MRO算法

    引子: 如图反映了python3中,几个类的继承关系和查找顺序.对于类A,其查找顺序为:A,B,E,C,F,D,G,(Object),这并不是一个简单的深度优先或广度优先的规律.那么这个顺序到底是如何 ...

  7. tomcat Win10 配置环境变量详解

    在Win10系统总该如何配偶之tomcat 环境变量?今天win10之家给大家带来了关于win10系统中配置tomcat环境的操作方法.在配置之前我们需要做以下几点: 步骤:安装和配置好了Java 的 ...

  8. WCF简单实例--用Winform启动和引用

    以订票为例简单应用wcf程序,需要的朋友可以参考下 本篇转自百度文档,自己试过,确实可以用. 以订票为例简单应用wcf 新建一个wcf服务应用程序 在IService1.cs定义服务契约 namesp ...

  9. 1 TCP/IP通信

    重点参考长链接http://blog.csdn.net/fengyuzhengfan/article/details/38830115 http://blog.csdn.net/Jsagacity/a ...

  10. oracle查询父节点及其下所有子节点

    1.我们的组织机构就是这种树形菜单的格式. . 2.执行sql: select ( select organization_name from SYS_ORGANIZATION where organ ...