SQL Server Dynamic Data Mask 防止沒有權限的帳號檢視敏感性資料
本文連結
開發環境
- VS 2017 Enterprise 15.9.1
- Entity Framework 6.2.0
- SQL Server 2016 Express Localdb
參考以下學習遮罩的使用方式
心得
1.遮罩設定
取消遮罩
GRANT UNMASK TO u
GRANT UNMASK TO u
恢復遮罩
REVOKE UNMASK TO u
REVOKE UNMASK TO u
移除欄位遮罩
ALTER TABLE [Customer] ALTER COLUMN Tel DROP MASKED
ALTER TABLE [Customer] ALTER COLUMN Tel DROP MASKED
u 是帳號
2.帳號有 sysadmin 和 db_owner 角色時,遮罩無效。
3.要有結構描述的標準 CREATE TABLE 和 ALTER 權限,就能建立含有動態資料遮罩。
4.新增、取代或移除資料行遮罩則需要資料表的 ALTER ANY MASK 權限和 ALTER 權限。
5.防止使用者檢視敏感機密資料,並非資料加密處理,無法保護資料;多查詢幾次,仍可推敲出結果
TSQL指令演練步驟
在 SSMS 執行語法,確定可行
建立資料表以及資料
USE [Lab.EF6.DynamicDataMask]
CREATE TABLE [dbo].[Customer] (
[ID] VARCHAR (11) NOT NULL,
[Name] NVARCHAR (10) NULL,
[Birthday] DATE MASKED WITH (FUNCTION = 'default()') NULL,
[Marriage] CHAR (1) MASKED WITH (FUNCTION = 'default()') NULL,
[Email] VARCHAR (50) NULL,
[Tel] VARCHAR (20) MASKED WITH (FUNCTION = 'default()') NULL,
[Salary] NUMERIC (13, 2) MASKED WITH (FUNCTION = 'default()') NULL,
[CreditCard] VARCHAR (19) NULL,
PRIMARY KEY CLUSTERED ([ID] ASC)
);
INSERT [Lab.EF6.DynamicDataMask].dbo.Customer(ID, Name, Birthday, Marriage, Email, Tel, Salary, CreditCard) VALUES (N'A123456789', N'小賴', '1961-06-07', N'0', N'a01@aa.bb', N'02-77203699', 3000000.00, N'1234-1234-5678-0001')
INSERT [Lab.EF6.DynamicDataMask].dbo.Customer(ID, Name, Birthday, Marriage, Email, Tel, Salary, CreditCard) VALUES (N'B123456789', N'小蔡', '1956-08-31', N'1', N'b01@aa.bb', N'03-77203699', 2000000.00, N'1234-1234-5678-0002')
INSERT [Lab.EF6.DynamicDataMask].dbo.Customer(ID, Name, Birthday, Marriage, Email, Tel, Salary, CreditCard) VALUES (N'C123456789', N'小明', '1942-03-16', N'1', N'c01@aa.bb', N'04-77203699', 1000000.00, N'1234-1234-5678-0003')
產生可以登入的帳號並授予權限
USE [master]
CREATE LOGIN UnmaskId WITH PASSWORD = N'pass@w0rd1~'
CREATE LOGIN MaskId WITH PASSWORD = N'pass@w0rd1~'
USE [Lab.EF6.DynamicDataMask]
CREATE USER UnmaskId FROM LOGIN UnmaskId
CREATE USER MaskId FROM LOGIN MaskId
--ALTER ROLE db_datareader ADD MEMBER UnmaskId
--ALTER ROLE db_datawriter ADD MEMBER UnmaskId
----
--ALTER ROLE db_datareader ADD MEMBER MaskId
--ALTER ROLE db_datawriter ADD MEMBER MaskId
GRANT SELECT ON Customer TO UnmaskId
GRANT SELECT ON Customer TO MaskId
--取消遮罩
GRANT UNMASK TO UnmaskId
--恢復遮罩
REVOKE UNMASK TO MaskId
產生不能登入的帳號並授予權限
USE [Lab.EF6.DynamicDataMask]
CREATE USER UnmaskId WITHOUT LOGIN
CREATE USER MaskId WITHOUT LOGIN
GRANT SELECT ON Customer TO UnmaskId
GRANT SELECT ON Customer TO MaskId
--取消遮罩
GRANT UNMASK TO UnmaskId
--恢復遮罩
REVOKE UNMASK TO MaskId
以上兩種授權的方式挑一種來做就可以了
切換帳號帳號來測試 Select,測試完畢後回到原本登入帳號
EXEC AS USER = 'UnmaskId'
SELECT
*
FROM Customer
REVERT
EXEC AS USER = 'MaskId'
SELECT
*
FROM Customer
REVERT
開發專案演練
專案位置
https://github.com/yaochangyu/sample.dotblog/tree/master/ORM/EF6/Lab.EF6.DynamicDataMask
把剛剛的步驟放到 SQL Project,按下發行就可以產生測試 DB
在測試專案,用 EF 工具把 Entity Model 倒進來
使用 sysadmin 帳號登入,切換身分讀取
[TestMethod] public void 切換沒有遮罩帳號() { using (var dbContext = new TestDbContext()) { if (dbContext.Database.Connection.State == ConnectionState.Closed) { dbContext.Database.Connection.Open(); } dbContext.Database.ExecuteSqlCommand("EXECUTE AS USER = 'UnmaskId'"); var customers = dbContext.Customers.AsNoTracking().ToList(); dbContext.Database.ExecuteSqlCommand("REVERT"); Assert.AreEqual("02-77203699", customers[0].Tel); } }
把建立 TestDbContext 的動作變成一個靜態方法
public partial class TestDbContext : DbContext { public TestDbContext(string connectionStringName = "TestDbContext") : base(connectionStringName) { } public static TestDbContext CreateDbContext(string connectionStringName = "TestDbContext") { var dbContext = new TestDbContext(connectionStringName); if (dbContext.Database.Connection.State == ConnectionState.Closed) { dbContext.Database.Connection.Open(); } return dbContext; } }
看起來就乾淨些
[TestMethod] public void 切換遮罩帳號() { using (var dbContext = TestDbContext.CreateDbContext()) { dbContext.Database.ExecuteSqlCommand("EXECUTE AS USER = 'MaskId'"); var customers = dbContext.Customers.AsNoTracking().ToList(); dbContext.Database.ExecuteSqlCommand("REVERT"); Assert.AreEqual("xxxx", customers[0].Tel); } }
使用遮罩帳號登入
切換身分看起來很不優雅,直接把使用組態設定的定義登入
[TestMethod] public void 登入遮罩帳號() { using (var dbContext = TestDbContext.CreateDbContext("TestDbContext_MaskId")) { var customers = dbContext.Customers.AsNoTracking().ToList(); Assert.AreEqual("xxxx", customers[0].Tel); } }
我用的三個連線字串定義
<connectionStrings> <add name="TestDbContext" connectionString="data source=(localdb)\mssqllocaldb;initial catalog=Lab.EF6.DynamicDataMask;integrated security=true;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient" /> <add name="TestDbContext_UnmaskId" connectionString="data source=(localdb)\mssqllocaldb;initial catalog=Lab.EF6.DynamicDataMask;integrated security=false;User Id=UnmaskId;Password=pass@w0rd1~;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient" /> <add name="TestDbContext_MaskId" connectionString="data source=(localdb)\mssqllocaldb;initial catalog=Lab.EF6.DynamicDataMask;integrated security=false;User Id=MaskId;Password=pass@w0rd1~;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient" /> </connectionStrings>
因為這是演練否則連線字串應該加密
若有謬誤,煩請告知,新手發帖請多包涵
Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET