我们利用MASKED
SQL Server 中的列功能在查询时隐藏敏感数据。但我们遇到过这样一种情况,即INSERT
作为语句的一部分执行的MERGE
是插入屏蔽UNMASK
值。即,即使以具有权限的用户身份查询表,新插入的值也会被视为屏蔽值。
具体来说,这种情况发生在:
- 一列是
MASKED
。 - 当前用户没有该
UNMASK
权限。 - 该
MERGE
语句的ON
子句使用了该MASKED
列。 - 该
MERGE
语句不匹配,因此落入该INSERT
部分。
以下是该问题的简单复现。
-- Define a test table with one non-masked and one masked column.
CREATE TABLE TestTable(
C1 NVARCHAR(100) MASKED WITH (FUNCTION = 'default()'),
C2 NVARCHAR(100) MASKED WITH (FUNCTION = 'default()'),
C3 NVARCHAR(100) -- Not masked
);
INSERT INTO TestTable
VALUES ('aaa', 'aaa', 'aaa'), ('bbb', 'bbb', 'bbb')
-- Print the current user and initial table content
SELECT SUSER_NAME() AS LoginName, USER_NAME() AS UserName;
SELECT *, 'No columns should be Masked' FROM TestTable
-- Create users with different permissions
CREATE USER user1 WITHOUT LOGIN
-- Setup permissions (No UNMASK permissions)
GRANT SELECT, UPDATE, INSERT TO user1;
-- Switch context to the user WITHOUT UNMASK permissions
EXECUTE AS USER = 'user1';
-- Show the user can only see masked data
SELECT SUSER_NAME() AS LoginName, USER_NAME() AS UserName;
SELECT *, 'Columns 1 & 2 should be Masked' FROM TestTable
-- Execute the merge, matching on the masked column
MERGE TestTable target
USING (
SELECT * FROM (VALUES
('bbb', 'bbb', 'bbb'), -- Will be merged
('ccc', 'ccc', 'ccc'), -- Will be inserted
('ddd', 'ddd', 'ddd')) -- Will be inserted
AS s (C1 ,C2 ,C3)
) AS source
ON (source.C1 = target.C1)
WHEN MATCHED THEN UPDATE SET
target.C2 = source.C2,
target.C3 = source.C3
WHEN NOT MATCHED BY TARGET
THEN INSERT (C1, C2, C3)
VALUES (source.C1, source.C2, source.C3);
-- A regular insert statement to check if masking applies there
INSERT INTO TestTable
VALUES ('eee', 'eee', 'eee')
-- Print the current user and current table content
SELECT SUSER_NAME() AS LoginName, USER_NAME() AS UserName;
SELECT *, 'Columns 1 & 2 should be Masked' FROM TestTable
REVERT; -- Back to the session user context
-- Print the current user and current table content
SELECT SUSER_NAME() AS LoginName, USER_NAME() AS UserName;
SELECT *, 'No columns should be Masked' FROM TestTable
-- Tidy up
DROP TABLE TestTable;
DROP USER user1;
最后一条语句的结果SELECT
如下所示。此 select 是以具有UNMASK
权限的用户身份执行的,但没有该权限的用户插入的两行仍然具有在显然被屏蔽的 中用作键的列MERGE
。我怀疑是因为屏蔽值是在 期间插入的MERGE
,而不是权限方面的问题。
这是一个已知问题吗?还是我做错了什么?
这是工作方式的结果
MERGE
。当定义了多个操作时,
CASE
执行计划中将评估表达式以确定要用于每个列的正确值。显然,更新操作通常会导致分配与插入操作应用于该源行时不同的值。正如文档所述(重点添加):
如果一个子句(您的案例中的插入操作)仅引用文字值(或来自非屏蔽源的值),而另一个子句使用屏蔽数据,则这种情况很不幸。结果
CASE
表达式将始终发出屏蔽数据。改变这种行为可能非常困难,但您仍然可以向 Microsoft 报告此问题。与此同时,使用单独的插入、更新和删除语句可能是一种可行的解决方法。