背景sql
假如咱们有关键数据存储在一个表里面,好比人员表中包含员工、部门和薪水信息。只容许用户访问各自部门的信息,可是不能访问其余部门。通常咱们都是在程序端实现这个功能,而在sqlserver2016之后也能够直接在数据库端实现这个功能。数据库
解决api
安全已是一个数据方面的核心问题,每一代的MS数据库都有关于安全方面的新功能,那么在Sql Server 2016,也有不少这方面的升级,好比‘Row Level Security’, ‘Always Encrypted’, ‘Dynamic Data Masking’, 和‘Enhancement of Transparent Data Encryption’ 等等都会起到安全方面的做用。本篇我将介绍关于Row Level Security (RLS--行级别安全), 可以控制表中行的访问权限。RLS 能使咱们根据执行查询人的属性来控制基础数据,从而帮助咱们容易地为不一样用户提透明的访问数据。行级安全性使客户可以根据执行查询的用户的特性控制数据库中的行。安全
为了实现RLS咱们须要准备下面三个方面:函数
逐一描述上面三个方面sqlserver
谓词函数测试
谓词函数是一个内置的表值函数,用于检查用户执行的查询访问数据是否基于其逻辑定义。这个函数返回一个1来表示用户能够访问。spa
安全谓词3d
安全谓词就是将谓词函数绑定到表里面,RLS提供了两种安全谓词:过滤谓词和阻止谓词。过滤谓词就是在使用SELECT, UPDATE, 和 DELETE语句查询数据时只是过滤数据可是不会报错。而阻止谓词就是在使用违反谓词逻辑的数据时,显示地报错而且阻止用户使用 AFTER INSERT, AFTER UPDATE, BEFORE UPDATE, BEFORE DELETE 等操做。code
安全策略
安全策略对象专门为行级别安全建立,分组全部涉及谓词函数的安全谓词。
实例
实例中咱们建立一个Person表和测试数据,最后咱们让不懂得用户访问各自部门的信息,代码以下:
Create table dbo.Person ( PersonId INT IDENTITY(1,1), PersonName varchar(100), Department varchar(100), Salary INT, User_Access varchar(50) ) GO INSERT INTO Person (PersonName, Department, Salary, User_Access) SELECT 'Ankit', 'CS', 40000, 'User_CS' UNION ALL SELECT 'Sachin', 'EC', 20000, 'User_EC' UNION ALL SELECT 'Kapil', 'CS', 30000, 'User_CS' UNION ALL SELECT 'Ishant', 'IT', 50000, 'User_IT' UNION ALL SELECT 'Aditya', 'EC', 45000, 'User_EC' UNION ALL SELECT 'Sunny', 'IT', 60000, 'User_IT' UNION ALL SELECT 'Rohit', 'CS', 55000, 'User_CS' GO
此时表已经被建立,而且插入了测试数据,执行下面语句检索有是有的记录:
SELECT * FROM Person
正如所示,目前有三个部门department(CS,EC,IT),而且User_Access列表示各自的用户组。让咱们建立三个测试用户数据的帐户语句以下:
--For CS department CREATE USER User_CS WITHOUT LOGIN --For EC department CREATE USER User_EC WITHOUT LOGIN -- For IT Department CREATE USER User_IT WITHOUT LOGIN
在建立了用户组之后,受权读取权限给上面是哪一个新建的用户,执行语句以下:
---授予select权限给全部的用户 GRANT SELECT ON Person TO User_CS GRANT SELECT ON Person TO User_EC GRANT SELECT ON Person TO User_IT
如今咱们建立一个谓词函数,该函数是对于查询用户是不可见的。
----Create function CREATE FUNCTION dbo.PersonPredicate ( @User_Access AS varchar(50) ) RETURNS TABLE WITH SCHEMABINDING AS RETURN SELECT 1 AS AccessRight WHERE @User_Access = USER_NAME() GO
这个函数是只返回行,若是正在执行查询的用户的名字与User_Access 列匹配,那么用户容许访问指定的行。在建立该函数后,还须要建立一个安全策略,使用上面的谓词函数PersonPredicate来对表进行过滤逻辑的绑定,脚本以下:
--安全策略 CREATE SECURITY POLICY PersonSecurityPolicy ADD FILTER PREDICATE dbo.PersonPredicate(User_Access) ON dbo.Person WITH (STATE = ON)
State(状态)为ON才能是策略生效,若是打算关闭策略,你能够改变状态为OFF。
再来看一下查询结果:
此次查询没有返回任何行,这意味着谓词函数的定义和策略的建立后,用户查询须要具备相应权限才能返回行,接下来使用不一样用户来查询这个数据,首先,咱们用用户User_CS来查询一下结果:
EXECUTE AS USER = 'User_CS' SELECT * FROM dbo.Person REVERT
正如所示,咱们看到只有三行数据数据该用户,User_CS,已经检索出来。所以,过滤函数将其余不属于该用户组的数据过滤了。
实际上这个查询执行的过程就是数据库内部调用谓词函数,以下所示:
SELECT * FROM dbo.Person
WHERE User_Name() = 'User_CS'
其余两组用户的查询结果是类似的这里就不一一演示了。
所以,咱们能看到执行查询根据用的不一样获得只属于指定用户组的指定数据。这就是咱们要达成的目的。
到目前为止,咱们已经演示了过滤谓词,接下来咱们演示一下如何阻止谓词。执行以下语句来受权DML操做权限给用户。
--受权DML 权限 GRANT INSERT, UPDATE, DELETE ON Dbo.Person TO User_CS GRANT INSERT, UPDATE, DELETE ON Dbo.Person TO User_EC GRANT INSERT, UPDATE, DELETE ON Dbo.Person TO User_IT
咱们用用户User_IT执行插入语句,而且插入用户组为UserCS的,语句以下:
EXECUTE AS USER = 'User_IT' INSERT INTO Person (PersonName, Department, Salary, User_Access) SELECT 'Soniya', 'CS', 35000, 'User_CS' REVERT
but,居然没有报错,插入成功了。
让咱们在检查一下用户数据插入的状况:
EXECUTE AS USER = 'User_IT' SELECT * FROM dbo.Person REVERT
奇怪,新插入行并无插入到该用户组'User_IT'中。而是出如今了'User_CS' 的用户组数据中。
--插入数据出如今了不一样的用户组 EXECUTE AS USER = 'User_CS' SELECT * FROM dbo.Person REVERT
经过上面的例子咱们发现,过滤谓词不不会阻止用户插入数据,所以没有错误,这是由于没有在安全策略中定义阻止谓词。让咱们加入阻止谓词来显示报错,有四个阻止谓词AFTER INSERT, AFTER UPDATE, BEFORE UPDATE, 和 BEFORE DELETE可使用。咱们这里测试使用AFTER INSERT 谓词。这个谓词阻止用户插入记录到没有权限查看的数据用户组。
添加谓词阻止的安全策略,代码以下:
--添加阻止谓词 ALTER SECURITY POLICY PersonSecurityPolicy ADD BLOCK PREDICATE dbo.PersonPredicate(User_Access) ON dbo.Person AFTER INSERT
如今咱们用以前相似代码再试一下,是否能够插入数据:
EXECUTE AS USER = 'User_CS' INSERT INTO Person (PersonName, Department, Salary, User_Access) SELECT 'Sumit', 'IT', 35000, 'User_IT' REVERT
擦,果真此次错误出提示出现了,阻止了不一样权限用户的插入。所以咱们能说经过添加阻止谓词,未受权用户的DML操做被限制了。
注意:在例子中每一个部门只有一个用户组成。若是在一个部门包含多个用户的状况下,咱们须要建立分支登陆为每一个用户都分配须要的权限,由于谓词函数应用于用户基础而且安全策略取决于谓词函数。
这里有几个行级别安全的限制:
总结
带有行级别安全功能的SQLServer2016,咱们能够不经过应用程序级别的代码修改来实现数据记录的权限控制。行级别安全经过使用谓词函数和安全策略实现,不须要修改各类DML代码,伴随着现有代码便可实现。