所有權鏈是SQL Server安全特性或安全風險

​譯自 K. Brian Kelley 的博文

我聽說過,SQL Server內部存在某種被稱爲“所有權鏈”的內容,但我並不知道那是什麼,或者其是怎麼工作的。我想知道其是一個安全風險還是一個安全特性。如果是安全特性,我怎麼使用它;如果是一個風險點,我想知道如何對其進行防禦。

所有權鏈是SQL Server內部的一個安全特性,而不是安全風險點。所有對象,如表和視圖,都有所有者。在SQL Server 2005 及以上,擁有者可能間接來自對象所述的架構的擁有者。讓我們更詳細的看看這一點。

每個對象都包含在一個架構中。架構是SQL Server 2005 及以上版本允許對對象進行邏輯分組的容器。例如,對於一個特別的應用,在公司內有兩種不同類型的用戶,一些來自市場部,一些來自人力資源。某些對象,如有關人事的信息表,邏輯上適合在人力資源類對象的容器中。其他對象適合在市場部相關對象的容器中,如一個跟蹤廣告活動的表格。通過使用架構,我們可以根據某個目的將對象分組。例如,我們可以創建兩個架構:

CREATE SCHEMA Marketing
GO
CREATE SCHEMA HumanResources
GO

架構需要有擁有者。如果創建架構的時候沒有指定擁有者(使用AUTHORIZATION關鍵詞設定擁有者),那麼創建架構的用戶將成爲擁有者。我們可以使用下面的語句查看架構及架構的擁有者:

SELECT 
      name AS SchemaName
      , schema_id
      , USER_NAME(principal_id) AS [Owner]
FROM    sys.schemas

下面是從測試庫中獲得的結果:

在SQL Server 2005 及以上版本中,當一個對象被創建時,並沒有必要一定要指定擁有者。SQL Server要做的是,假設對象的擁有者是其所屬架構的擁有者。例如,在下面的創建語句中,沒有指定擁有者。因此,那些對象的擁有者對應其所屬架構的擁有者:

CREATE TABLE HumanResources.TestTable (
      TableValue INT );
GO
CREATE PROC Marketing.QueryTestTable
AS
BEGIN
    SELECT  TableValue
    FROM    HumanResources.TestTable;
END
GO

第一個對象,一個被成爲Test Table 的表,在HumanResources架構下被創建。第二個對象,一個被命名爲QueryTestTable的存儲過程,在Marketing 架構下被創建。因爲沒有其他T-SQL語句被執行來指定每個對象對應的擁有者,在考慮到所有權鏈時,SQL Server 將使用各自對象所屬架構的所有者作爲對象的所有者。可以通過ALTER AUTHORIZATION 顯式改變一個對象的所有者,如下(CREATE USER語句創建一個有效用戶,以便創建表的所有者):

CREATE USER TestUser WITHOUT LOGIN
GO
CREATE TABLE Marketing.OwnedTable(
      TabeleValue INT
);
GO
ALTER AUTHORIZATION ON Marketing.OwnedTable TO TestUser

我們可以通過查詢 sys.objects 和 sys.schemas,查看對象,及其所屬架構,並且誰是有效對象擁有者。如果沒有顯式指定對象擁有者,那麼對象中的principal_id列將是NULL。通過使用COALESE,我們可以先查看sys.objects的principal_id,然後再查看sys.schemas。

SELECT
      so.[name] AS ObjectName
      ,sch.[name] AS SchemaName
      ,USER_NAME(COALESCE(so.principal_id,sch.principal_id)) AS [Owner]
FROM sys.objects so
JOIN sys.schemas sch
ON so.[schema_id]=sch.[schema_id]
WHERE [type] IN ('U','P');

下面是test數據庫查詢的結果:

一旦我們理解了對象的有效所有者,我們可以查看所有權鏈。當下面事實發生時,產生所有權鏈:

  • 一個對象引用另外一個對象,如存儲過程引用表

  • 兩個對象有相同的所有者

這種情況下,僅僅需要第一個對象的權限。以前面 Marketing.QueryTestTable存儲過程爲例,其查詢HumanaResources.TestTable。如果這兩個對象的所有者相同,那麼就形成了所有權鏈。當所有權鍊形成時,SQL Server 將僅僅檢查第一個對象的權限。假設,因爲所有者相同,這個引用是刻意設計的,將不會檢查引用對象的權限。因此,在給定的例子中,如果一個用戶有執行Marketing.QueryTestTable的權限,SQL Server將允許執行HumanResources.TestTable,只要查詢來自存儲過程。

例如,如果我們想控制表的訪問,使得用戶必須通過存儲過程才能訪問表,這個T-SQL創建了一個角色,並且賦予了需要的權限給角色:

CREATE ROLE GrantPermissions;
GO
GRANT EXECUTE ON Marketing.QueryTestTable TO GrantPermissions;
GO

通過所有權鏈的使用,我們可以強制從存儲過程中訪問。這是很有幫助的,例如,如果我們想控制一個表中數據的插入、更新或者刪除。一個很好的例子是應用每次刪除一行數據。假設用戶顯示賦予訪問表的權限,那麼用戶可能意外的刪除表中所有的數據,因爲忘記了WHERE條件。解決方案是創建一個存儲過程,基於傳入參數,刪除合適的記錄。存儲過程僅僅允許刪除一行。因此,一個終端用戶不會意外刪除表中所有記錄,因爲用戶沒有操作表的權限。如果用戶嘗試這樣操作,他或她將得到一個拒絕訪問的錯誤。然而,用戶可以執行存儲過程,做什麼由存儲過程嚴格控制。這是所有權鏈提供的好處。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章