SQL Server On Linux(9)—— SQL Server On Linux安全性(2)——Row Level Security

本人新书上市,请多多关照:《SQL Server On Linux运维实战 2017版从入门到精通》

在这里插入图片描述

Row Level Security,行级安全性,简称RLS,是从SQL Server 2016引入。相对于过去,仅能对对象或语句进行权限控制从而对表的全部数据行实现权限管理而言,现在可以使用RLS针对特定的行进行授权。当然,视图也是可以做到的,但是RLS可能是更好的选择,因为RLS还实现了一些额外的功能用于在执行前或执行后进行一些阻止操作。

RLS演示

  在介绍内部知识之前,先做一个演示,可能会更加深刻。但是在此之前先下载另外一个新的演示数据库WideWorldImporters ,下载方法可以参考前面的文章:SQL Server On Linux(3)——SQL Server 2019 For Linux 下载并部署示例数据库

创建用于RLS操作的SQL 登录账号

USE master
GO
IF NOT EXISTS (SELECT 1 FROM sys.server_principals WHERE  name = N'RLSTest')
BEGIN
   CREATE LOGIN RLSTest
   WITH PASSWORD = N'abc.123',
        CHECK_POLICY = OFF,
        CHECK_EXPIRATION = OFF,
        DEFAULT_DATABASE = WideWorldImporters;
END
GO

创建映射到登录名的用户并添加到已存在的角色中

  这个角色映射到销售区域(sales territories)

USE WideWorldImporters;
GO
DROP USER IF EXISTS RLSTest
GO
CREATE USER RLSTest FOR LOGIN RLSTest
GO
ALTER ROLE [Great Lakes Sales] ADD MEMBER RLSTest  --Great Lakes Sales已存在于该数据库中
GO

创建安全策略

   使用RLS需要创建一个SQL Server函数,用于确定查询可以访问哪些数据行。所以需要创建一个安全策略映射到这个函数。

-- 删除已存在的安全策略和函数
--
DROP SECURITY POLICY IF EXISTS [Application].FilterCustomersBySalesTerritoryRole
GO
DROP FUNCTION IF EXISTS [Application].DetermineCustomerAccess
GO
-- 创建用于RLS的函数
--
CREATE FUNCTION [Application].DetermineCustomerAccess(@CityID int)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN (SELECT 1 AS AccessResult
        WHERE IS_ROLEMEMBER(N'db_owner') <> 0
         OR IS_ROLEMEMBER((SELECT sp.SalesTerritory
                          FROM [Application].Cities AS c
                           INNER JOIN [Application].StateProvinces AS sp
                           ON c.StateProvinceID = sp.StateProvinceID
                           WHERE c.CityID = @CityID) + N' Sales') <> 0
           )
GO
-- 创建使用RLS函数的安全策略
--
CREATE SECURITY POLICY [Application].FilterCustomersBySalesTerritoryRole
ADD FILTER PREDICATE [Application].DetermineCustomerAccess 
(DeliveryCityID)
ON Sales.Customers
GO

  现在解释一下这个函数,它获取CityID的值,然后从Cities表和StateProvinces表中获取city的SalesTerritory名。然后把’Sales’追加到名字的末尾。这就任何在GreatLakes区域的CityID都会返回到GreatLakesSales中。
  安全策略从[Sales].[Customers]表中返回DeliveryCityID。通过这个策略,如果以RLSTest用户登录并查询Customers表,那么只会返回符合规则的数据。下面就来测试一下。

测试效果

  首先使用sa来测试:

SELECT COUNT(*) FROM Sales.Customers;

在这里插入图片描述
  然后我们以RLSTest身份来执行,这里并没有修改任何查询语句。

GRANT SELECT, UPDATE ON Sales.Customers TO [Great Lakes Sales];
GO
-- 以 RLSTest身份执行
EXECUTE AS USER = 'RLSTest'
GO

SELECT COUNT(*) FROM Sales.Customers;
GO
--收回权限
REVERT
GO

在这里插入图片描述

  上图可以看到,用不同的用户执行相同的语句返回了不一样的结果,证明函数起效了。下面来做专业一点的介绍。

扫描二维码关注公众号,回复: 10043773 查看本文章

RLS技术说明

  在过去,为了实现不同角色的用户访问不同的数据,即使是同一个表,也要进行多个视图控制或者架构等改变,这个操作需要从前端到后端一并实现,变更起来也很不方便。从SQL 2016开始,引入了RLS,相对于过去,RLS提供了相当简化的实现方式。
  RLS提供了基于数据行的读写访问控制,并且最小化架构、应用程序或者查询语句的变更。

RLS概念

  RLS有三个核心概念:

  1. 谓词函数:Predicate function,用于实现访问控制逻辑的表值内联函数(inline table-valued funcation)
  2. 安全谓词:Security predicate,把谓词函数应用于表。
  3. 安全策略:Security policy,安全谓词的集合。

  回看前面的谓词函数,需要注意的是函数要使用SCHEMABINDING,以免底层表的变更带来影响,但是仅仅创建函数是不够的,需要某个方式把函数应用到表上,这个时候就引出了安全策略。安全策略是安全谓词的集合,上面例子中仅对一个表进行操作,但是实际上可以对多个表进行操作,比如可以写成:

CREATE SECURITY POLICY AccountAndRepPolicy
ADD FILTER PREDICATE dbo.LimitAccountAccess(RepID) ON dbo.AccountReps,
ADD FILTER PREDICATE dbo.LimitAccountAccess(RepID) ON dbo.Accounts
WITH (STATE = ON);

  这个安全策略把谓词函数dbo.LimitAccountAccess()应用到两个表中。通过ADD FILTER PREDICATE来实现。

阻止谓词

  下面来介绍一下RLS对“写”操作的行为,阻止谓词显式阻止违反该谓词的写入操作,包含AFTER INSERT、AFTER UPDATE、BEFORE UPDATE、BEFORE DELETE。

  • AFTER INSERT 和 AFTER UPDATE 谓词可以防止用户将行更新为违反该谓词的值
  • BEFORE UPDATE 谓词可以防止用户更新当前违反该谓词的行
  • BEFORE DELETE 谓词可以阻止删除操作

  实现这种阻止操作,需要在安全策略中使用BLOCK谓词,在FILTER谓词过滤掉不可见的数据之后,再进行阻止,因为FILTER并不阻止数据插入。可以创建另外一个谓词函数,然后如下面添加ADD BLOCK PREDICATE来实现即可。这里就不演示了。

CREATE SECURITY POLICY [Application].FilterCustomersBySalesTerritoryRole
ADD FILTER PREDICATE [Application].DetermineCustomerAccess (DeliveryCityID) ON Sales.Customers
ADD BLOCK PREDICATE 阻止函数 ON Sales.Customers
GO

总结

  RLS是其中一个官方和SQL Server专家都推荐使用的安全功能,它类似触发器,也类似视图,RLS的其中一个亮点是简化了开发的工作量和复杂度。由于其功能强大,很多细节不打算在这里讲解,在后续再做一些案例演示,这篇的主要目的是引出这个功能,之所以没有做更多演示的原因是官方文档:行级安全性还是比较难度懂,我也在想如何能够在严谨的前提下做到易懂,所以在没做到这个程度之前先不引入得太深。

发布了192 篇原创文章 · 获赞 1268 · 访问量 250万+

猜你喜欢

转载自blog.csdn.net/DBA_Huangzj/article/details/86624204
今日推荐