行级安全(Row

Posted 王思聪6

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了行级安全(Row相关的知识,希望对你有一定的参考价值。

通过授予和拒绝(Grant/Deny)命令控制用户的权限,只能控制用户对数据库对象的访问权限,这意味着,用户访问的粒度是对象整体,可以是一个数据表,或视图等,用户要么能够访问数据库对象,要么没有权限访问,就是说,一个数据库对象,通过授予和拒绝用户的权限/角色(Permission或Role),无法使特定的数据行只允许特定身份的人访问,但是,该需求可以使用安全策略(Security Policy)实现。

当启用行级安全(Row-Level Security,简称RLS)时,Security Policy在数据行级别上控制用户的访问,粒度是数据行,控制用户只能访问数据表的特定数据行。断言(Predicate )是逻辑表达式,返回的结果是布尔(boolean)值:true 或false。在SQL Server 2016中,RLS是基于安全断言(Security Predicate)的访问控制,Security Predicate是由内联表值函数实现的,当逻辑表达式返回结果时,安全断言的结果是True;当逻辑表达式不返回任何结果时,安全断言的结果是False。如果安全策略(Security Policy)被禁用,那么用户总是访问所有数据行,跟数据表上不关联任何安全策略一样。

 

实现RLS,必须显式定义三个组件:

  • 数据表(Base Table):用于存储数据行,在该表上创建Security Policy,使用RLS控制用户能够访问的数据行;
  • 断言函数(Predicate Function):是内联表值函数,用于执行安全断言,Security Policy调用该函数过滤数据行或阻塞写操作;
  • 安全策略(Security Policy):将数据表和断言函数绑定,并设置安全断言的类型;

一,内联表值函数定义安全断言(Security Predicate)

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

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

复制代码
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\'; 
复制代码

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

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

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

1,过滤断言(Filter Predicate)

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

过滤断言(Filter Predicate)定义一个Security Policy,在Base Table上执行select,update和delete命令时,Security Policy透明地过滤数据行,应用程序不会意识到Filter操作的存在;应用程序能够插入任何数据,不管数据是否被过滤掉。

2,阻塞断言(Block Predicate)

阻塞断言(Block predicates)将Update操作拆分成两个独立的操作:Before Update 和 After Update。

Block Predicate影响所有的写操作,有四种阻塞操作:

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

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

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

三,使用Security Policy控制用户只能访问指定的数据

1,创建数据表,并插入数据

 View Code

2,创建User,并授予查询权限

复制代码
--create user
create user Sales1 without login;
create user Manager without login; --grant permission GRANT SELECT ON Sales TO Manager; GRANT SELECT ON Sales TO Sales1;
复制代码

3,创建内存表值函数,用于过滤数据行,返回Security Predicate 的结果

强烈推荐创建一个单独的Schema,用于RLS对象(Predicate Function和 Security Policy),本例中创建RLS Schema。

复制代码
--create schema
create schema rls;  
authorization dbo;
 
--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\';
复制代码

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

在新建的Security Policy中,将Base Table和Security Predicate 绑定,添加Filter Predicate,使用dbo.Sales作为过滤条件,启用新建的Security Policy

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

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

复制代码
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; 
复制代码

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

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

四,维护安全策略(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任何数据行,看到的数据表的全部数据行。

 

参考文档:

CREATE SECURITY POLICY (Transact-SQL)

Row-Level Security

以上是关于行级安全(Row的主要内容,如果未能解决你的问题,请参考以下文章

使用 MS SQL 的 JAX-RS 中的行级安全性

JOOQ 中的行级安全性实现

Innodb 和mylsam存储引擎

Innodb 和mylsam存储引擎

BigQuery 行级安全权限

为啥没有为 Postgres 视图启用行级安全性?