1 t-sql sql-server for-xml-path for-json dynamic-data-masking
我正在使用 SQL Server Standard(64 位)14.0.1000.169 在 QA 服务器上使用屏蔽数据库。这是我的结构:
CREATE TABLE [dbo].[Test](
[Column1] [VARCHAR(64)] NULL,
[Column2] [VARCHAR(64)] NULL
)
GO
INSERT INTO [dbo].[Test]
VALUES ('ABCDEFG', 'HIJKLMN')
Run Code Online (Sandbox Code Playgroud)
我用以下代码屏蔽了该列:
ALTER TABLE [dbo].[Test]
ALTER COLUMN [Column1] VARCHAR(64) MASKED WITH (FUNCTION = 'default()');
Run Code Online (Sandbox Code Playgroud)
当我使用非允许的用户执行以下查询时,它按预期工作:
SELECT [Column1], [Column2]
FROM [dbo].[Test]
FOR JSON PATH
-- RESULT: '[{"Column1":"xxxx", "Column2":"HIJKLMN"}]'
Run Code Online (Sandbox Code Playgroud)
但当同一个非允许用户将结果保存在变量中时(主要目标),它不起作用:
DECLARE @var VARCHAR(64)
SET @var = (SELECT [Column1], [Column2] FROM [dbo].[Test] FOR JSON PATH)
SELECT @var --it should show a valid JSON...
-- RESULT: 'xxxx' <-- JSON LOSES ITS STRUCTURE
-- DESIRED RESULT: '[{"Column1":"xxxx", "Column2":"HIJKLMN"}]' <-- VALID JSON
Run Code Online (Sandbox Code Playgroud)
主要问题:当 SELECT 中出现屏蔽列并且存在“FOR JSON PATH”子句时,JSON 会失去其结构。
我们希望获得有效的 JSON,无论数据列是否被屏蔽,或者是否sa是用户。
我已经使用 NVARCHAR 或在屏蔽列中执行 CAST 进行了测试,但获得所需结果的唯一方法是在使用“FOR JSON PATH”子句之前使用 #tempTable。
如何在没有松散 JSON 结构的情况下 SELECT 屏蔽列并将其保存到 VARCHAR 变量?任何帮助将不胜感激。
注意:默认情况下允许 SA 用户查看未屏蔽的数据(因此 JSON 不会丢失其结构),但我们希望在非允许用户上执行它并返回有效的 JSON,而不仅仅是“xxxx”。
它确实看起来是一个错误。重现在这里。虽然见下文,但不太确定。
当使用FOR JSON或 就此而言FOR XML,作为顶级SELECT构造时,与将其放置在子查询中或将其分配给变量相比,使用不同的代码路径。这是裸 .txt 文件中每行限制 2033 字节的原因之一FOR JSON。
似乎正在发生的情况是,在 bare 的情况下FOR JSON,数据屏蔽发生在计划的顶部,在运算符Compute Scalar之前的运算符中JSON SELECT。因此屏蔽仅发生在一列上。
而当放入子查询中时,UDX则使用函数运算符。问题是,这是在创建JSON 或 XML之后Compute Scalar发生的,而它应该被推到计划中的下方。UDXUDX
我建议您在Azure 反馈网站上向 Microsoft 提交该错误。
稍微讨论了一下之后,我现在实际上认为这不是一个错误。没有嵌套的情况看起来确实是一个错误。
从文档中:
每当您投影引用定义了数据屏蔽函数的列的表达式时,该表达式也将被屏蔽。无论使用什么函数(默认、电子邮件、随机、自定义字符串)来屏蔽引用的列,结果表达式将始终使用默认函数进行屏蔽。
因此,当您选择任何屏蔽列时,即使在正常情况下SELECT,如果您在该列上使用函数,则屏蔽总是在任何其他函数之后发生。换句话说,在读取数据时不应用屏蔽,而在最终输出到客户端时应用屏蔽。
使用子查询时,数据被输入到UDX函数运算符中。编译器现在感觉到最终结果集是正常的SELECT,只是它需要屏蔽来自屏蔽列的任何最终结果。因此,整个 JSON 被屏蔽为一个 blob,类似于UPPER(yourMaskedColumn). 有关示例,请参阅此 fiddle 中的XML 计划。
但是当使用 bare 时FOR JSON,它在编译器看来是正常的SELECT,只是最终输出更改为 JSON(顶级SELECT运算符不同)。所以掩蔽发生在该点之前。在我看来,这是一个错误。
FOR XML当您使用使用相同机制的 时,该错误甚至更加严重。如果你使用嵌套,那么无论你是否嵌套它,FOR XML ..., TYPE你都会得到结果。<masked />这又是因为查询计划显示了在UDX. 而如果你不使用, TYPE那么这取决于你是否嵌套它。参见小提琴。