天天看點

SQL Server安全(10/11):行級别安全(Row-Level Security)

在保密你的伺服器和資料,防備目前複雜的攻擊,SQL Server有你需要的一切。但在你能有效使用這些安全功能前,你需要了解你面對的威脅和一些基本的安全概念。這篇文章提供了基礎,是以你可以對SQL Server裡的安全功能充分利用,不用在面對特定威脅,不能保護你資料的功能上浪費時間。

不像其它一些工業強度的資料庫伺服器。SQL Server對于單個資料記錄,缺少内建機制,稱作行級别安全(Row-Level Security)。這篇文章會探尋為什麼你可能想使用這樣的行級别顆粒的資料通路安全和你如何能實施行級别安全。

行級别安全

在SQL Server 2000和SQL Server 2005釋出之間,微軟認真對待安全。比爾蓋茨早在2002年給公司寫了它的“可信賴計算機”備忘錄,是以SQL Server 2005收到大量的安全修正。一個新的安全戰略是比早起版本做出更多顆粒度的授權架構,讓你可以顆粒度的完全控制誰可以用哪個對象。

對增加安全粒度的一個明顯遺漏是它沒有擴充到行級别。在表級别你有很多控制通路選項,當SQL Server在表裡沒有内建通路控制機制,通常稱為“行級别安全”。在很多場景裡這是個問題,尤其是有管控要求保護特定資料的時候。例如,在醫療資料庫裡的病人表有所有就診病人的資料,但隻有醫療管理者有所有病人的通路,醫生和護士應該隻有它們直接照顧病人的通路。有很多其它場景需要允許通路表的子集資料,或甚至到單元格級别。當SQL Server沒有實作行級别安全的内建方式。

提示:

表包含行和列,是以微軟使用單元格(cell)術語來指定位于表裡一行的一列裡的資料。它是必須要的區分,因為有些場景,你需要安全在表裡的各個單元格(單個資料項)。在接下來的文章你會學到更多。

行級别安全在資料庫裡提供單條記錄上的細粒度通路控制。理想結果是通過查詢的執行上下文篩選的記錄,是以使用者隻需通路有許可的記錄。這個篩選使用SQL Server裡同樣的安全功能,控制到其它資料庫、伺服器對象和在這些對象上操作的通路。

由于SQL Server缺少内建的行級别安全,開發人員和管理者需要設計出各種聰明和創造性的技術來解決這個缺點。盡管這些技術常需要不少額外工作來配置,為了實施顆粒度的控制,不是在表裡所有記錄的控制,隻授予表裡子集記錄的通路,這樣做是值得的。這個技術可以相對簡單,也可以和你需要的一樣複雜,使用安全标簽和通路控制的層級目錄。安全标簽描述資料項目的敏感性,在這篇文章裡你會學習到這個技術。

這裡我們假設行級别安全是在伺服器級别的最佳實施。你可以在應用程式級别控制資料庫對象的通路,但你必須在使用資料庫的每個應用程式裡實作安全層。在資料庫裡的行級别安全意味着安全對應用程式是透明的,應用程式開發者不需要,甚至留意通路控制所在的地方。

微軟最終開始宣布在SQL Server裡行級别安全的缺少,受雲主機資料庫需要驅動。它們首次給SQL Azure資料庫增加了行級别安全,也會是SQL Server 2016的一部分。

通過各個使用者或組的,幾乎都需要行級别安全技術控制通路,這就是說應用程式需要為每個使用者使用特定的辨別連接配接到受保護的資料庫,這個辨別通常是Windows或SQL Server登入。這就是說,通常你不能應用程式實作行級别安全,應用程式使用中間層連接配接池,它必須使用單個辨別來通路資料庫。但這個通常不是問題,因為通過行級别安全的資料庫保護通常有其它需要終端使用者的需求,例如審計。

用視圖實作行級别安全

稍後你将學到,SQL Server 2016實作了内建的安全。但是直到它的釋出,你遷移資料庫到它裡面,我們需要自己實作保護。我們來看一個使用常見技術實作行級别安全的簡單實作。盡管它很簡單,它可以作為更為複雜方法實作的基礎。假設公司有包含敏感資訊的客戶記錄,例如信用額度和重罪定罪(felony convictions)。(是的,我知道,這有點做作,但我們開始吧)。隻有系統管理者(或董事會)和配置設定到客戶的公司代表才可以看到客戶資料,所有這些都是存儲在單個Customer表。

代碼10.1展示了建立樣本資料庫和單個Customer表的代碼,并插入一些資料。一切都相當簡單,除了在表了加了UserAccess字段。這是資料庫代碼用來限制通路的字段。記住這隻是個簡單的例子,有很多其它方法來實作這個。

1 IF DB_ID('RowLevelSecurityDB') IS NOT NULL DROP DATABASE RowLevelSecurityDB;
 2 CREATE DATABASE RowLevelSecurityDB;
 3 GO
 4 USE RowLevelSecurityDB;
 5 GO
 6 
 7 -- Create the sample table that we want to protect with row-level security
 8 CREATE TABLE Customer (
 9     CustId INT, 
10     Name NVARCHAR(30), 
11     City NVARCHAR(20), 
12     CreditLimit MONEY,
13     SocialSecurityNumber NCHAR(11), 
14     FelonyConvictions INT,
15     UserAccess NVARCHAR(50)
16 );
17 GO
18 
19 -- Add some data to the Customer table
20 INSERT INTO dbo.Customer
21        (CustId, Name, City, CreditLimit, SocialSecurityNumber, FelonyConvictions, UserAccess)
22 VALUES (1, N'Don Kiely', N'Fairbanks', 5.00, N'123-45-6789', 17, N'UserOne'),
23        (2, N'Kalen Delaney', N'Seattle', 500000.00, N'987-65-4321', 0, N'UserOne'),
24        (3, N'Tony Davis', N'Cambridge', 5000.00, N'', 0, N'UserTwo'),
25        (4, N'E.T. Barnette', N'Fairbanks', 0.00, N'555-66-7777', 47, N'UserOne'),
26        (5, N'Soapy Smith', N'Sitka', 0.00, N'222-33-4444', 32, N'UserTwo');       

代碼10.1:建立樣本資料庫和表,并插入樣本資料

自定義行級别安全架構通常需要資料庫架構的一些層級改變,額外的UserAccess字段就其中方法之一。另一個處理更複雜情景的常見做法是建立多對多的表來連接配接巷道使用者或角色。SQL Server有這個工具,按你的需要的想法來解決這個問題。

所有到表的資料通路會通過視圖;代碼10.2建立MyCustomersView視圖,基于使用者執行上下文篩選資料。CREATE VIEW代碼有趣的部分是WHERE子句。它使用USER_NAME函數獲得執行上下文的使用者名。然後SELECT語句傳回在UserAccess字段裡使用者名比對的所有行。或者,如果使用者是db_owner資料庫成員或伺服器sysadmin角色成員,視圖會傳回表裡的所有行。

1 IF object_id(N'dbo.MyCustomers', 'V') IS NOT NULL
 2     DROP VIEW dbo.MyCustomers;
 3 GO
 4 
 5 CREATE VIEW dbo.MyCustomersView AS
 6     SELECT CustId, Name, City, CreditLimit, SocialSecurityNumber, FelonyConvictions, UserAccess FROM dbo.Customer 
 7     WHERE UserAccess = USER_NAME() OR
 8         IS_ROLEMEMBER('db_owner') = 1 OR
 9         IS_SRVROLEMEMBER('sysadmin') = 1;
10 GO      

代碼10.2:建立MyCustomersView視圖,基于執行上下文在表裡篩選資料

這是配置儲存資料和提供對它通路所有需要的代碼。代碼10.3建立2個資料庫使用者。在這個例子裡使用者不需要映射到伺服器層級登入,但在大多數情況下需要這樣做。然後代碼拒絕所有到這個Customer表的使用者通路,在視圖上授予select許可。這個拒絕了直接從表的直接通路,但允許通過視圖的通路。如果你想使用者通過視圖修改資料,你也可以授予這些許可。

1 CREATE USER UserOne WITHOUT LOGIN;
2 CREATE USER UserTwo WITHOUT LOGIN;
3 GO
4 
5 -- Set permissions
6 DENY SELECT, INSERT, UPDATE, DELETE ON dbo.Customer TO UserOne, UserTwo;
7 GRANT SELECT ON dbo.MyCustomersView TO UserOne, UserTwo;
8 GO      

代碼10.3:建立2個資料庫使用者,限制它們到Customer表的通路,在視圖上授予select許可。

現在你可以測試行級别安全架構,使用代碼10.4。第一個SELECT語句作為sysadmin測試視圖。你會看到如插圖10.1的結果集,這個語句傳回表裡的所有行。

1 -- Test as admin
 2 SELECT * FROM dbo.MyCustomersView;    -- Should succeed and return all rows
 3 
 4 -- Test as regular users
 5 EXECUTE AS USER = 'UserOne';
 6 SELECT * FROM dbo.Customer;            -- Should fail
 7 SELECT * FROM dbo.MyCustomersView;    -- Should succeed and return 3 rows
 8 REVERT;
 9 GO
10 
11 EXECUTE AS USER = 'UserTwo';
12 SELECT * FROM dbo.Customer;            -- Should fail
13 SELECT * FROM dbo.MyCustomersView;    -- Should succeed and return 2 rows
14 REVERT;
15 GO      

代碼10.4:測試簡單的行級别安全,第一次以sysadmin,然後以資料庫的每個使用者。

SQL Server安全(10/11):行級别安全(Row-Level Security)

插圖10.1:以sysadmin使用視圖,選擇資料的結果:所有行傳回。

代碼10.4裡的第2段測試在UserOne的執行上下文的裡的行級别安全視圖。在這個例子裡,有兩個SELECT語句。第一個直接從表讀取資料,測試DENY許可。第二個測試視圖使用。如預料的一樣,第一個語句失敗(插圖10.2),第二個語句傳回3條資料(插圖10.3),UserAccess等于UserOne的行。我們有行級别安全!

SQL Server安全(10/11):行級别安全(Row-Level Security)

插圖10.2:當以UserOne測試表和視圖時,失敗和成功資訊。

SQL Server安全(10/11):行級别安全(Row-Level Security)

插圖10.3:當以UserOne執行時,從MyCustomersView視圖傳回的行

在代碼10.4裡最後一段代碼再次直接從表擷取任何資料失敗,但這次視圖傳回UserTwo通路Customer表的2條資料,如插圖10.4所示。

SQL Server安全(10/11):行級别安全(Row-Level Security)

插圖10.4:以UserTwo執行時,從MyCustomersView視圖傳回行。

對于實施行級别安全,你有非常簡單的架構。它是簡單的,但對于了解基本概念很有用。但這樣做的方法有一些問題:

  • 如果你需要保護多個表,你會用不同程度的複雜邏輯來實作視圖來允許不同的使用者和角色通路保護的資料。當架構修改時,表對應的視圖也要随着多次改變。
  • 這個例子是基于使用者名稱的,并假定每一行隻有一個通路使用者。很可能你也需要通過角色篩選的方法,當沒有唯一使用者名時,你也要處理。
  • 當使用者名修改時,你要在一個或多個表裡修改資料。

還有其它一個問題,取決于你的特殊情景。

但你可以容易建立這個情景,增加你任何需要或想要的複雜層級。想法的偉大源泉是來自微軟的行級别安全白皮書,在下一部分會談到,它介紹了複雜行級别安全的實作方法,剛才的例子是簡單的。

來自微軟的最佳行級别安全實踐

一個行級别安全更複雜,現實世界在用的已經超出了這系列文章的範圍。但微軟已經生成這個樣本作為白皮書的一部分,在分類資料庫裡實施行和單元級别安全。

上述連結的行級别安全白皮書是原先是為SQL Server 2005寫的,但微軟為它保留了多年。最後一次更新在2012年1月,即使現在的SQL Server 2014也是同樣适用。

在這個白皮書裡介紹的方法,是為公共部分的安全需要和有最進階别的安全需要的分類資料庫所設計。它适用安全标簽和視圖來提供顆粒通路控制,和超過行級别對各個單元格的通路保護,如果施行完整架構。白皮書介紹的安全标簽如下:

安全标簽是一條資訊,它描述了資料條目(一個對象)的敏感度。它是包含從一個或多個目錄标記的字元。使用者(送出者)有同樣标記的許可描述。每個送出者的許可可以通過它們自己的标簽。送出這的标簽和對象的标簽進行比較決定是否可以通路這個對象。

使用的例子保護層級的架構,使用類似米國政府喜歡的SECRET,TOP SECRET和UNCLASSIFIED分類。架構允許多個通路标準,例如這些安全分類受與不同項目或部門聯合的進一步限制。例如,有最高機密類别的在NSA裡的人不能通路FBI的最高機密檔案。

實施這種,對于行和單元級别的安全的跨領域,分等級的安全架構需要更多代碼,包括建立資料庫對象,用來資料儲存和提供資料通路——主要是表和視圖——還有維護系統的代碼。白皮書裡包含了很多代碼!另外在白皮書裡的代碼,微軟建立了SQL Server标簽安全工具箱,放在CodePlex上,包括上面的引用白皮書。工具箱包括标簽政策設計器應用程式,文檔和使用

描述在不同方法裡實作的例子。SQL Server标簽政策設計器的例子如插圖10.5所示。這個應用程式提供讓你定義你分類的漂亮界面。然後工具會生成SQL代碼來建立所有需要的對象,在你選擇的資料庫裡直接運作代碼,或者儲存為腳本檔案,用于後期修改或執行。

SQL Server安全(10/11):行級别安全(Row-Level Security)

插圖10.5:SQL Server标簽政策設計器使用者界面,用白皮書裡樣本架構類别。

即使你不需要白皮書裡介紹的這類靈活和非常顆粒度的安全架構,你可以通過閱讀白皮書學到更多,探尋工具箱的内容。在你自己資料庫和應用程式裡用于實作行級别安全的選項僅限于在SQL Server裡你用各個工具的想法。

SQL Server 2016裡的行級别安全

對于創造性,自定義行級别安全架構的需求已經過時,因為有SQL Server 2016了。微軟宣布這個版本包含内建的行級别安全,這是像其它資料庫引擎Oracle已經擁有多時,期待已久的功能。

這個功能目前還在開發(現在已經釋出),是以這篇文章不會太深入讨論。但這個方法肯定有效,你定義安全謂語篩選作為内聯,表值函數,當使用者或應用通路受保護的資料時,它成為安全政策的一部分觸發。代碼10.5展示了一些在SQL Server 2016的CTP版本裡使用的行級别安全代碼,摘自線上幫助裡行級别安全話題預告。當表裡的SalesRep列和執行查詢的使用者,或是管理者使用者,這個安全政策包含單個傳回1的篩選謂語。這個和剛才使用UserAccess列和視圖來篩選資料的代碼類似。

1 CREATE SCHEMA Security;
 2 GO
 3 
 4 CREATE FUNCTION Security.fn_securitypredicate(@SalesRep AS sysname)
 5     RETURNS TABLE
 6 WITH SCHEMABINDING
 7 AS
 8     RETURN SELECT 1 AS fn_securitypredicate_result 
 9         WHERE @SalesRep = USER_NAME() OR USER_NAME() = 'Manager';
10 GO
11 
12 CREATE SECURITY POLICY SalesFilter
13     ADD FILTER PREDICATE Security.fn_securitypredicate(SalesRep) ON dbo.Sales
14     WITH (STATE = ON);
15 GO      

代碼10.5:建立安全政策來實施内建的行級别安全的SQL Server 2016代碼

當為行級别安全實作商務邏輯,不需要在像在分類資料庫白皮書裡介紹方法對象的昂貴支援,以内聯表值函數,建立安全謂語篩選的能力提供了巨大的靈活性。對應用通路資料透明是件好事:應用程式不需要知道資料庫裡的任何行級别安全。

微軟在SQL Server 2016裡的行級别安全的設計目标是性能和自定義實作。這個拭目以待,但我确認會有一些性能低效的自定義代碼降低它們!釋出後,SQL Server 2016的新功能會大大減少行級别安全需要的工作。

小結

在SQL Server 2014和先前版本裡缺少對行級别安全的支援是在内建在SQL Server 2005和後續版本裡的其它顆粒度安全架構的一個明顯遺漏。但聰明的開發人員幾年來發明很多聰明架構來讓你下至表裡的行和單元格級别,保持資料安全,有不同級别的複雜度和靈活度。然而,還是值得努力去建立自定義架構,基于其它釋出的架構或你自己建立的,這樣的話,你可以更精細的保護你的資料。SQL Server 2016通過資料庫引擎内建對行級别安全的支援讓這些變得簡單。

原文連結

http://www.sqlservercentral.com/articles/Stairway+Series/128866/

注:此文章為

WoodyTu

學習MS SQL技術,收集整理相關文檔撰寫,歡迎轉載,請在文章頁面明顯位置給出此文連結!

若您覺得這篇文章還不錯請點選下右下角的推薦,有了您的支援才能激發作者更大的寫作熱情,非常感謝!

繼續閱讀