欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  数据库

SQL Server 2016:行级安全

程序员文章站 2024-01-16 17:48:46
...

对于SQL Server,一个常见的批评是,其安全模型只能识别表和列。用户如果希望以行为单位应用安全规则,就需要使用存储过程或表值

对于SQL Server,一个常见的批评是,其安全模型只能识别表和列。用户如果希望以行为单位应用安全规则,就需要使用存储过程或表值函数来模拟,然后找一种方法,确保它们不会被绕开。在SQL Server 2016中,那不再是个问题。

实现

SQL Server 2016(及SQL Azure)中的 行级安全 基于一个专门设计的内联表值函数。该函数要么返回一个只包含值1的行,要么不返回结果,这取决于用户访问的行是否是相关行。请看下面的函数:

CREATE FUNCTION Security.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';

这段代码的意思是,当前用户必须是一名经理,或者是一名与记录相关的推销员。该函数没有访问行本身,但用户可以使用参数传入相应的列(比如,SalesRep)。例如:

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

实际效果

在使用行级安全时,用户无法看到他们不能访问的行。这就好像在访问表时自动增加一个额外的、安全相关的where子句。

由于其作用像一个where子句,所以有一些局限。例如,如果用户在那个列上使用了全文搜索索引,,那么数据就可能泄露。此外,数据库还可能遭受旁路攻击。微软写道:

通过使用精心设计的查询,可以导致信息泄露。例如,SELECT 1/(SALARY-100000) FROM PAYROLL WHERE 会让一个恶意用户知道John Doe的工资是10万美元。即使有一个恰当的安全谓词阻止恶意用户直接查询其它人的工资,他也可以在查询返回“除数为0”的异常时确定工资数额。

此外,信息也可能通过统计对象泄露。为了降低风险,查看受保护列统计信息的用户必须是“表的所有者,或者是服务器固有角色sysadmin、数据库固有角色db_owner或db_ddladmin的成员”。

中间层应用程序

截至目前,我们讨论的场景是用户以自己的身份登录。在中间层应用程序中,所有人都共享同一个数据库账户,实现行级安全需要额外的步骤。

对于中间层应用程序,推荐的设计模式是将 CONTEXT_INFO 的值设置为连接打开时用户特定于应用程序的用户id。然后,安全函数就可以引用CONTEXT_INFO的值。例如:

CREATE FUNCTION Security.fn_securitypredicate(@AppUserId int) RETURNS TABLE WITH SCHEMABINDING AS RETURN SELECT 1 AS fn_securitypredicate_result WHERE DATABASE_PRINCIPAL_ID() = DATABASE_PRINCIPAL_ID('dbo') -- 应用程序上下文 AND CONVERT(int, CONVERT(VARBINARY(4), CONTEXT_INFO())) = @AppUserId; -- AppUserId (int)占4个字节 GO CREATE SECURITY POLICY Security.SalesFilter ADD FILTER PREDICATE Security.fn_securitypredicate(AppUserId) ON dbo.Sales WITH (STATE = ON);

该方法的前提是,用户无法执行任意SQL,因为那会让他们可以随意更改CONTEXT_INFO。

查看英文原文: SQL Server 2016: Row-Level Security

本文永久更新链接地址