資源管理員安全性
資源管理員會使用現有的 SQL Server 安全性機制,例如驗證、權限等級和擁有權鏈結。這個主題將識別出您應該在設定和使用資源管理員時考慮的層面,以便確保有效處理可能產生的安全性問題。
考量因素
您必須考量下列資源管理員的設計和實作元素,以便盡可能在使用這項功能時確保安全:
權限
資源集區和工作負載群組名稱
分類使用者定義函數
權限
下面是變更或檢視資源管理員設定的必要權限:
若要變更資源管理員組態,使用者必須擁有 CONTROL SERVER 權限。當您執行任何資源管理員 DDL 陳述式時,系統就會檢查權限。
若要檢視動態管理檢視所提供的使用中組態,使用者必須擁有 VIEW SERVER STATE 權限。
我們建議將撰寫或變更資源管理員組態的能力提供給有經驗的資料庫管理員。
資源集區和工作負載群組名稱
所有資源集區和工作負載群組名稱都是公開的。因此,建立集區和群組時,您應該選擇不會透露在伺服器上執行之應用程式本質等相關資訊的名稱。例如,名為 CompanyPayroll 的工作負載群組就會明顯指出使用此工作負載群組之應用程式的本質和重要性。
分類使用者定義函數
分類使用者定義函數 (UDF) 會儲存在 master 資料庫中。
這個函數的設計和實作與 LOGON 觸發程序很相似,而且會在 LOGON 觸發程序之後執行,當做登入程序的一部分。此函數會在提出要求之工作階段的登入內容中執行,而且分類必須在實際建立工作階段之前完成。因此,在分類函數內產生而且通常會送達使用者的所有訊息 (例如錯誤訊息和來自 PRINT 陳述式的訊息) 都會轉至 SQL Server 錯誤記錄檔。
注意 |
---|
雖然這個資源管理員版本會實作 schemabinding 來限制可從分類 UDF 內部進行的呼叫,但是此函數傳回的所有資料不一定都安全。如需詳細資訊,請參閱<撰寫分類函數的考量>。 |
請注意分類使用者定義函數行為的下列層面:
資源管理員預設會在登入使用者的內容中將此函數當做分類的一部分執行,或以指定使用者的身分執行此函數 (如果在此函數中指定了 EXECUTE AS 的話)。
當資源管理員將此函數當做分類的一部分執行時,它就不會檢查分類 UDF 的 EXECUTE 權限。不過,此函數所參考的所有物件都會受標準權限檢查的限制,而這些檢查會根據擁有權鏈結允許存取。
如果使用範圍超過資源管理員分類的範圍,將函數當做資源管理員分類註冊並不會影響其權限等級。
資源管理員的擁有權鏈結
當資源管理員分類正在執行時,您可以仰賴預設以結構描述為基礎的擁有權鏈結或使用 EXECUTE AS,將結構描述的存取權提供給單一使用者。下列程式碼範例和註解將說明擁有權鏈結如何在資源管理員中運作。
[!附註]
下列範例會假設 SQL 登入已啟用。
下列程式碼會建立擁有 master 存取權的結構描述使用者 (SchemaUser1、SchemaUser2)。
use master
go
CREATE LOGIN SchemaUser1 WITH PASSWORD='your password here';
CREATE USER SchemaUser1 FOR LOGIN [SchemaUser1];
CREATE LOGIN SchemaUser2 WITH PASSWORD='your password here';
CREATE USER SchemaUser2 FOR LOGIN [SchemaUser2];
go
下列程式碼會建立擁有預設登入權限的使用者 (NormalUser1)。
CREATE LOGIN NormalUser1 WITH PASSWORD='your password here';
CREATE USER NormalUser1 FOR LOGIN [NormalUser1];
go
下列程式碼會建立結構描述 (Schema1、Schema2) 並將它們對應至已建立的結構描述使用者。此外,它也會針對結構描述建立資料表 (groupTable)。
CREATE SCHEMA Schema1 AUTHORIZATION SchemaUser1
CREATE TABLE groupTable (uname sysname, gname sysname);
CREATE SCHEMA Schema2 AUTHORIZATION SchemaUser2
CREATE TABLE groupTable (uname sysname, gname sysname);
go
下列程式碼會將值加入至 groupTable。
INSERT Schema1.groupTable VALUES(N'NormalUser1',N'Group1');
INSERT Schema2.groupTable VALUES(N'NormalUser1',N'Group2');
go
此時,Schema1 和 Schema2 分別為 SchemaUser1 和 SchemaUser2 擁有。下一個程式碼範例會建立將用來存取 Schema1 和 Schema2 的函數。
CREATE FUNCTION Schema1.classifier() RETURNS sysname WITH SCHEMABINDING AS
BEGIN
DECLARE @n sysname
SELECT @n = gname FROM Schema1.groupTable WHERE uname = SUSER_NAME()
SELECT @n = gname FROM Schema2.groupTable WHERE uname = SUSER_NAME()
RETURN @n
END
go
下列程式碼會將上述函數註冊為分類 UDF。請注意,SchemaUser1 沒有 Schema2 的存取權限。
ALTER RESOURCE GOVERNOR WITH (CLASSIFIER_FUNCTION=Schema1.classifier);
ALTER RESOURCE GOVERNOR RECONFIGURE
go
若要進行測試,您可以嘗試從另一個用戶端連接以 NormalUser1 的身分登入。開啟 Windows 事件檢視器。您應該會在應用程式記錄中看見分類失敗項目。NormalUser1 會透過從 Schema1.classifier 的擁有權鏈結,繼承 Schema1.groupTable 的存取權限。不過,Schema1 沒有存取 Schema2.groupTable 的權限。
若要進行另一項測試,請將 SELECT 權限授與 Schema2.groupTable 的 SchemaUser1。
GRANT SELECT ON Schema2.groupTable TO SchemaUser1
go
以 NormalUser1 的身分登入。您應該會再次在事件記錄中看見分類失敗項目。因為伺服器會檢查 NormalUser1 是否擁有 SELECT 權限 (不會繼承自 SchemaUser1),所以導致這項失敗發生。
在下一個程式碼範例中,我們會建立另一個分類函數。此時,登入會被授與 EXECUTE AS SchemaUser1 的權限。
CREATE FUNCTION Schema1.classifier2() RETURNS sysname WITH SCHEMABINDING, EXECUTE AS 'SchemaUser1' AS
BEGIN
DECLARE @n sysname
SELECT @n = gname FROM Schema1.groupTable WHERE uname = SUSER_NAME()
SELECT @n = gname FROM Schema2.groupTable WHERE uname = SUSER_NAME()
RETURN @n
END
go
ALTER RESOURCE GOVERNOR WITH (CLASSIFIER_FUNCTION=Schema1.classifier2);
ALTER RESOURCE GOVERNOR RECONFIGURE;
go
由於新的函數會在 SchemaUser1 的內容中執行,而且 SchemaUser1 擁有 Schema2.groupTable 的 SELECT 權限,因此 NormalUser1 登入的 Schema1.classifier2() 函數將順利執行。
再次以 NormalUser1 的身分登入並檢查事件記錄是否有分類失敗。
[!附註]
由於 NormalUser1 沒有被授與 Schema1.classifier2 函數的 EXECUTE 權限,因此 NormalUser1 無法將此函數當做特定查詢執行。
如需詳細資訊,請參閱<擁有權鏈結>。
測試分類函數
您應該先測試並最佳化分類函數,然後再將它用於分類內送要求。撰寫不夠周全的函數可能會將系統呈現為因逾時而無法使用,而且可能會公開組態資訊。您可以在啟用資源管理員時,使用專用管理員連接 (DAC) 來疑難排解分類函數,因為這個連接不受分類限制。我們建議您在伺服器上啟用 DAC。如需詳細資訊,請參閱<使用專用管理員連接>。
[!附註]
如果 DAC 無法用於疑難排解,其他選項就是在單一使用者模式中重新啟動系統。雖然單一使用者模式不受分類限制,但是您無法在資源管理員分類執行時進行診斷。