SQLServer 行级安全性 - 从数据库内实施

Ama*_*mam 3 sql-server row-level-security sql-server-2016

在单个 SQL Server 2016 数据库上运行多租户应用程序。我有一个 RLS(行级安全性)谓词customer_id(每个租户唯一)并且该列存在于所有表中。

CREATE FUNCTION dbo.[RLSPredicate] (@CustomerId bigint)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN SELECT 1 AS RLSPredicateResult WHERE (@CustomerId = 
CAST(SESSION_CONTEXT(N'customer_id') AS bigint))

GO

 -- two table example
 CREATE SECURITY POLICY [dbo].[RLSPolicy] 
 ADD FILTER PREDICATE [dbo].[RLSPredicate] ([customer_id]) ON [dbo].[user],  
 ADD FILTER PREDICATE [dbo].[RLSPredicate] ([customer_id]) ON [dbo]. 
  [user_email]
  WITH (STATE = ON, SCHEMABINDING = ON)
  GO

  -- Sample Query 
  EXEC sp_set_session_context @key=N'customer_id', @value='1231312'
  select top 1000 * from [user] where customer_id = 1231312
Run Code Online (Sandbox Code Playgroud)

使用上面的设计,EXEC sp_set_session_context总是需要在任何用户查询命中数据库之前执行,但是我们有应用团队忘记添加代码的情况EXEC sp_set_session_context在新项目中情况。

问题是无法保证进入数据库的查询总是包含EXEC sp_set_session_context在其中。查询以各种形式出现,EXEC, sp_executesql, adhoc 等。

我想知道是否有任何方法可以重新设计过滤谓词,以便从数据库中强制执行 RLS,并EXEC sp_set_session_context在每次查询之前删除运行的依赖性。

有超过 50 万个customer_id值。

Ste*_*o64 5

我认为您应该使用登录触发器并SET CONTEXT_INFO引用 BoL

将最多 128 字节的二进制信息与当前会话或连接相关联。

然后您可以通过使用 select 调用该函数来检索数据

IE SELECT CONTEXT_INFO()

然后,您可以使用从与 Row Level Security 的连接中调用的数据来实现您想要的过滤。

如果您运行的是 SQL Server 2016 或更高版本,则应改用更现代的session_context()函数 - 请参阅Aaron Bertrand 的Phase out CONTEXT_INFO() in SQL Server 2016 with SESSION_CONTEXT()