问题描述
请考虑以下内容:有两个表,表A和表B。在表A上实现RLS。
然后,在表B上通过内部联接将表B链接到表A来实现RLS。 猜猜在表B的谓词函数中什么会忽略表A的RLS。
-
似乎,您需要在表B的谓词功能中重新应用表A的RLS。这是设计使然吗?
-
在谓词函数中将表B链接到表A时,是否可以设置一些标志或“ with”子句以强制执行现有的RLS?
-
我做错什么了吗?
用于创建和填充表的SQL脚本。
CREATE TABLE [dbo].[Securities]
(
[SecurityId] [int] NOT NULL,[Security] [varchar](50) NOT NULL,[IssueCurrency] [varchar](3) NOT NULL,CONSTRAINT [PK_Securities]
PRIMARY KEY CLUSTERED ([SecurityId] ASC)
WITH (PAD_INDEX = OFF,STATISTICS_NORECOMPUTE = OFF,IGNORE_DUP_KEY = OFF,ALLOW_ROW_LOCKS = ON,ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[Prices]
(
[SecurityId] [int] NOT NULL,[PriceDate] [date] NOT NULL,[Price] [numeric](18,4) NULL,CONSTRAINT [PK_Prices]
PRIMARY KEY CLUSTERED ([SecurityId] ASC,[PriceDate] ASC)
WITH (PAD_INDEX = OFF,ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Prices] WITH CHECK
ADD CONSTRAINT [FK_Prices_Securities]
FOREIGN KEY([SecurityId]) REFERENCES [dbo].[Securities] ([SecurityId])
GO
ALTER TABLE [dbo].[Prices] CHECK CONSTRAINT [FK_Prices_Securities]
GO
INSERT INTO [dbo].[Securities] ([SecurityId],[Security],[IssueCurrency])
VALUES (1,'Project Power','CAD'),(2,'Fractured Ltd','AUD'),(5,'Eddy Security','USD'),(6,'Foxtrot','USD')
GO
INSERT INTO Prices ([SecurityId],[PriceDate],[Price])
VALUES (1,'2020-08-05',13.2500),(1,'2020-08-06',13.3500),'2020-08-07',13.0500),23.9500),24.1500),22.0500),105.1500),106.3500),105.0500),36.2500),36.3500),35.0500)
用于创建谓词功能和安全策略的SQL脚本。
/*
drop security policy if exists Policy_Securities
go
drop function if exists dbo.rlsSecurities
go
*/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION rlsSecurities (@IssueCurrency varchar(3))
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
SELECT 1 AS UserAccess
WHERE
(SESSION_CONTEXT(N'UserGroup') = 'Internal') or
(
@IssueCurrency = 'USD' --non-internal group can only view securities where IssueCurrency='USD'
)
go
CREATE SECURITY POLICY Policy_Securities
ADD FILTER PREDICATE dbo.rlsSecurities(IssueCurrency) ON dbo.Securities
WITH(STATE = ON)
go
EXEC sys.sp_set_session_context @key=N'UserGroup',@value='XYZ'
SELECT SESSION_CONTEXT(N'UserGroup')
SELECT * FROM Securities
SELECT s.Security,p.*
FROM Securities s
INNER JOIN Prices p ON s.SecurityId = p.SecurityId --RLS on table Prices is enforced thru inner join.
SELECT * FROM Prices --Currently no RLS on tblComp.
--Now I want to implement RLS on Prices as well.
drop security policy if exists Policy_Prices
go
drop function if exists dbo.rlsPrices
go
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
create FUNCTION rlsPrices (
@SecurityId int)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
SELECT 1 as UserAccess
where @SecurityId in (select SecurityId from dbo.Securities) --This doesn't work even though RLS on table Securities already exists.
--where --This works but it requires reapplying RLS on table Securities.
-- (SESSION_CONTEXT(N'UserGroup') = 'Internal') or
-- (
-- @SecurityId In (select SecurityId from dbo.Securities where IssueCurrency = 'USD') --non-internal group can only view securities where IssueCurrency='USD'
-- )
go
CREATE SECURITY POLICY Policy_Prices
ADD FILTER PREDICATE dbo.rlsPrices(SecurityId) ON dbo.Prices
WITH(STATE = ON)
go
exec sys.sp_set_session_context @key=N'UserGroup',@value='XYZ'
select SESSION_CONTEXT(N'UserGroup')
select * from Prices --RLS not enforced
解决方法
您没有做错任何事情。
当在策略的范围/执行中执行tvf时,似乎RLS并未考虑谓词表值函数中引用的表上的任何现有策略。 在普通查询中执行时,tvf可以正常工作(执行tvf中的引用表{ie。Securities}的策略):
--standalone...check the execution plan,predicate of Securities.PK_Securities index scan is the function/policy on currency='USD'
select p.*
from Prices as p
cross apply dbo.rlsPrices(p.SecurityId)
如果您检查执行计划:
--filter policy on Prices
select * from Prices
您将仅看到对价格的聚集索引扫描,因为从价格到证券(SecurityId)存在FK,所以根本不检查证券表。 即使您删除FK,“价格与证券”之间的连接也会丢失任何有关证券的RLS谓词。
简而言之,筛选器策略不是嵌套/继承/级联的,无论是否设计使然。.尚不清楚。