SQL Server 2008的元數據安全
細粒度權限架構的一個優點就是 SQL Server不僅保護元數據,也保護數據。在 SQL Server 2005之前,能夠訪問數據庫的用戶可以看到數據庫中所有對象的元數據,無論該用戶是否可以訪問其中的數據或是否能夠執行存儲過程。
SQL Server 2008 仔細檢查數據庫中主體所擁有的各種權限,僅當主體具有所有者身份或擁有對象的某些權限時,才會顯示該對象的元數據。還有一種 VIEW DEFINITION 權限,即使沒有該對象的其他權限,利用它也能查看元數據信息。
這種保護擴展到了某些操作返回的出錯消息,這些操作試圖訪問或更新用戶無權訪問的對象。SQL Server 不會確認確實存在一份名為 Address 的表,使攻擊者確信自己的方向是正確的,而是返回提示各種可能性的出錯消息。例如,如果用戶無權訪問數據庫中的對象,并且試圖訪問 Address 表,則 SQL Server 將顯示下列出錯消息:
Msg 3701, Level 14, State 20, Line 1
Cannot drop the table 'Address', because it does not exist or you do not have permission.
通過這種方式,攻擊者無法確認是否真的存在 Address 表。但是,通過排查問題,仍然有很小的攻擊可能性。
SQL Server Agent 代理
關于 SQL Server 2008 中的授權模型,一個最佳示例就是 SQL Server Agent??梢远x往往與 Windows 登錄相關的各種憑證,且它們將鏈接到具有必要權限以執行一個或多個 SQL Server Agent 步驟的用戶。然后,SQL Server Agent 代理將憑證與工作步驟鏈接到一起,以提供必要的權限。
這就以顆粒方式實現了“最少特權”原則:只授予工作步驟必要的權限,僅此而已??梢噪S意創建代理,并使其與一個或多個 SQL Server Agent 子系統相關聯。這與 SQL Server 2000中的全能式代理帳戶截然不同,后者允許用戶在 SQL Server Agent 的任何子系統中創建工作步驟。
注釋 在 SQL Server 2000中升級服務器時,將創建單代理帳戶,而且所有的子系統都將被分配這個單代理帳戶,以使現有的工作繼續運行。升級完成后,將創建憑證和代理帳戶,通過實施更安全、粒度更細的代理集,以保護服務器資源。
圖6為 Management Studio 中的 Object Explorer,它顯示了 SQL Server Agent 中可用的子系統列表。每個子系統都可以擁有一個或多個與之相關的代理,以為工作步驟分配適當的權限。該架構有一個例外,即 Transact-SQL 子系統需要在模塊所有者的權限下執行,這與 SQL Server 2000 中的方式相同。

圖1:可與代理相關聯的 SQL Server Agent 子系統
新安裝了 SQL Server 之后,只有 System Administrator 角色有權維護 SQL Server Agent工作,而且只有 sysadmins 能夠使用 Management Studio Object Explorer 中的管理窗格。SQL Server 2008 允許用戶利用其它一些角色授予各種級別的權限??梢苑峙溆脩?SQLAgentUser、SQLAgentReaderRole 或 SQLAgentOperator 角色,其中每一個角色都會分配級別逐漸提高的權限,以創建、管理及運行工作,也可分配 MaintenanceUser 角色,它擁有 SQLAgentUser 的所有權限,還能創建維護計劃。
當然,sysadmin 角色的成員可以在任何子系統中隨意執行任何操作。要授予其他任何用戶使用子系統到權限,需要創建至少一個代理帳戶,這可授予訪問一個或多個子系統的權利。圖7顯示了如何將代理帳戶 MyProxy 分配多個主體,這里包括一位用戶和一個角色。代理帳戶使用憑證,將其鏈接到帳戶,通常是鏈接到域帳戶,并且擁有在操作系統中執行各種任務的權限,這些權限也是子系統所必需的。每個代理都擁有一個或多個與之相關的子系統,它們使主體能夠運行這些子系統。

圖2:用于各種子系統的 SQL Server Agent 代理帳戶
下列代碼就是實施圖7所示架構所需的 Transact-SQL 代碼。首先創建憑證和一個數據庫對象,后者將提供操作系統帳戶鏈接,該帳戶有權在子系統中執行所需動作。然后它添加 MyProxy 代理帳戶,該帳戶其實只是憑證的友好名稱。接著,它將代理分配兩個主體,就是 SQL Server 登錄和定制角色。最后,它使代理與4個 SQL Server Agent 子系統相關聯。
|
CREATE CREDENTIAL MyCredential WITH IDENTITY = 'MyDOMAIN\user1' sp_grant_proxy_to_subsystem @proxy_name = 'MyProxy', |
SQL Server Management Studio 完全支持憑證和代理的創建,如圖8所示。這將創建與上一段代碼相同的代理。

圖3:SQL Server Management Studio 中的SQL Server Agent 新代理
代理不只是操作系統中杜絕安全問題的一種方式。如果與代理一起使用的憑證沒有 Windows 權限,如通過網絡寫入目錄的權限,則該代理也不會有此權限。也可利用代理為xp_cmdshell 授予有限的執行權限,因為它是黑客最喜歡利用的工具,只要他們能夠成功威脅到 SQL Server 計算機的安全,就會進一步利用該工具將其威脅范圍擴展到網絡空間。代理提供了該領域的保護機制,因為縱使主體在網絡上不受任何限制,例如域管理員主體,通過代理執行的任何命令也只擁有憑證帳戶的有限權限。
#p#
執行上下文
一直以來,SQL Server 都支持所有權鏈的概念,它可確保管理員和應用程序開發人員能夠在數據庫的入口點提前檢查權限,而不是用來提供所有被訪問對象的權限。只要調用模塊(存儲過程或函數)或視圖的用戶擁有模塊的執行權限或視圖的選擇權限,而且模塊或視圖的所有者曾是被訪問對象的所有者(所有權鏈),則不會檢查基本對象的任何權限,而且調用者將收到請求的數據。
假如因為代碼的所有者沒有被引用對象的所有權,而導致所有權鏈被打斷,SQL Server 將按照調用者的安全上下文檢查權限。如果調用者擁有訪問對象的權限,SQL Server 將返回數據。如果沒有此權限,SQL Server 將提示出錯。
所有權鏈有一些局限性:它只適用于數據操作,而不適用于動態 SQL。而且,如要跨越所有權邊界訪問對象,就不可能實現所有權鏈。因此,權限提前檢查行為只適用于某些場合。
SQL Server 2008 能夠利用執行上下文標記模塊,這樣模塊中的語句即可供與調用用戶并列的特殊用戶執行。通過這種方式,調用用戶仍然需要模塊的執行權限,而SQL Server 將按照模塊的執行上下文檢查模塊中語句的權限。可以利用此行為客服所有權鏈的某些缺陷,因為它適用于模塊中的所有語句。想要執行權限提前檢查的管理員可以利用執行上下文達到這一目的。
在定義用戶定義函數(除了內聯的表值)、存儲過程和觸發器時,可以利用 EXECUTE AS 子句指定SQL Server 要使用哪個用戶的權限驗證對對象以及過程引用數據的訪問:
CREATE PROCEDURE GetData(@Table varchar(40)) |
SQL Server 2008 提供了4種 EXECUTE AS 選項。
EXECUTE AS CALLER 指定代碼在模塊調用者的安全上下文中執行。不會出現假冒的現象。調用者必須擁有所有被引用對象的訪問權限。但是,SQL Server 只檢查被打斷的所有權鏈的權限,假如代碼的所有者也擁有基本對象的所有權,則只檢查該模塊的執行權限。這就是向后兼容性的默認執行上下文。
EXECUTE AS 'user_name' 指定代碼在指定用戶的安全上下文中執行。如果不想使用所有權鏈,這就是一個不錯的選項。否則,可以創建擁有運行代碼以及創建定制權限集所需權限的用戶。
EXECUTE AS SELF 是一個快捷符號,用于為創建或更改模塊的用戶指定安全上下文。在內部,SQL Server 將保存與模塊關聯的實際用戶名,而不是保存“SELF”。
EXECUTE AS OWNER 指定安全上下文就是模塊執行時模塊當前所有者的安全上下文。如果模塊沒有所有者,則將使用包含架構所有者的上下文。如想修改模塊的所有者,而且不想修改模塊本身,這就是一個絕佳選項。
利用 EXECUTE AS 選項更改用戶上下文時,模塊的創建者和更改者必須擁有指定用戶的IMPERSONATE 權限。不能從數據庫中刪除指定用戶,除非將所有模塊的執行上下文更改為其他用戶。
用戶/架構分離
SQL Server 2000 沒有架構的概念,而 ANSI SQL-99 規范將架構定義為單個主體所擁有的所有數據庫對象集合,而且該主體形成了對象的一個命名空間。架構就是數據庫對象的容器(如表、視圖、存儲過程、函數、類型和觸發器等)。它的功能與.NTE Framework 和 XML 中的命名空間函數非常類似,該函數可將對象進行分組,以便數據庫能夠重用對象名稱,如允許在一個數據庫中同時存在 dbo.Customer 和 Fred.Customer,也可對不同所有者的對象進行分組。
注意:需要用到目錄視圖,如 sys.database_sys.principals、sys.schemas 和sys.objects 等。原因在于 sysobjects 舊系統表不支持架構,因此不支持U/S分離。此外,不贊成使用舊目錄視圖,在 SQL Server 的未來版本中它們將被刪除。
圖9的頂端就是 SQL Server 2000中的架構工作原理。當管理員在數據庫中創建 Alice 用戶時, SQL Server 將自動創建 Alice 架構,它隱藏于 Alice 用戶后面。如果 Alice 登錄了正在運行 SQL Server 但沒有數據庫所有權的服務器,而且創建了表1,則該表單實際名稱為 Alice.Table1。這也適用于 Alice 創建的其他對象,如 Alice.StoredProcedure1 和 Alice.View1。如果 Alice 是數據庫所有者或 sysadmin,她創建的對象將成為 dbo 架構的一部分。雖然我們習慣說 dbo 擁有對象,但這是同一碼事。

圖4:SQL Server 2000 and 2008中的用戶/架構/對象
需要修改對象的所有權時,例如 Alice 離開公司而 Lucinda 接手了 Alice 的工作,此時SQL Server 2000 中用戶和架構的融合會產生一個問題。系統管理員必須將 Alice 擁有的所有對象的所有者改為Lucinda。更成問題的是,則 Lucinda 擁有了表的所有權后,還必須將任何引用 Alice.Table1 的Transact-SQL 或客戶端應用程序代碼改為引用 Lucinda.Table1。根據 Alice 擁有的對象數量以及內部嵌有該名稱的應用程序數量,這可能是一項繁重的工作。Microsoft 公司一直建議內置的 dbo 用戶要擁有所有的數據庫對象,以避免產生這些問題。與修改許多對象和客戶端應用程序相比,修改數據庫的所有權要容易得多。
注意:不要被 SQL Server 2000 CREATE SCHEMA 語句迷惑。它只是一種簡單的方法,用以創建特殊用戶擁有的表和視圖,以及授予權限。可以利用該語句命名架構的所有者,但不能命名架構。SQL Server 仍不可避免地將所有者鏈接到架構,這要面對修改所有權帶來的所有問題。
SQL Server 2008 通過分離用戶和架構克服了這些問題,并實施了 SQL-99 架構,如圖9底部所示。利用新增的 CREATE USER DDL 創建 Alice 新用戶時,SQL Server 不再自動創建使用相同名稱的架構。反之,必須顯式創建架構,并將其所有權分配用戶。由于圖示的所有的數據庫對象都包含于 Schema1 架構中,就是 Alice 最初擁有的架構,因此只須將架構的所有者改為 Lucinda,就可以方便地修改所有架構對象的所有權。每位用戶也都被分配默認架構,這樣 SQL Server 將假定沒有架構引用且按照名稱引用的任何對象都位于默認架構中。在圖9的底部,如果 Alice 使用 Schema1 作為默認架構,她就可將該表命名為 Schema1.Table1 或Table1。Carol 用戶可能沒有與其名字關聯的默認架構,必須將該表命名為 Schema1.Table1。沒有默認預定義架構的任何用戶都使用 dbo 作為默認架構。
在 SQL Server 2008 中,完全合格的對象名稱由4部分組成,這與舊版SQL Server 中的對象名稱類似:
server.database.schema.object |
與舊版類似,如果對象所在服務器與運行代碼的服務器同名,則可忽略服務器名稱。如果連接打開了同名數據庫,則可忽略數據庫名稱。如果使用當前用戶的默認架構或架構為 dbo 所擁有,則可忽略架構名稱,因為這是 SQL Server 嘗試消除對象名稱歧義時最后用過的架構。
可以利用 CREATE USER 語句而非 sp_adduser 語句創建新用戶。此系統存儲過程仍然是為了實現向后兼容性,但已進行了少許修改,以遵循用戶與架構分離的新原則。sp_adduser 創建的架構與新用戶名或應用程序角色同名,并將該架構作為用戶的默認架構,這與 SQL Server 2000 的行為類似,但提供了分離的架構。
注意:使用 ALTER AUTHORIZATION 語句時,可能會產生這種情況:“您”擁有“我的”架構中的表(或反之)。這個問題具有重大的隱含意義。例如,誰擁有該表的觸發器,您還是我?底部的代碼行可以設計得非常巧妙,以發現架構范圍對象或類型的真正所有者。有兩種方式可以避開此問題:
利用 OBJECTPROPERTY(id,”OwnerId”)發現對象的真正所有者。
利用 TYPEPROPERTY(type,”OwnerId”)發現類型的真正所有者。
SQL Server 2008 利用同義詞幫助減少擊鍵次數??梢岳脙刹糠?、三部分或四部分完整對象名為任何對象創建同義詞。SQL Server 使用同義詞訪問已定義的對象。在下列代碼中,“History”同義詞表示在AdventureWorks 數據庫中指定的 schema.table。SELECT 語句返回EmployeeDepartmentHistory 表的內容。
|
USE AdventureWorks CREATE SYNONYM History FOR HumanResources.EmployeeDepartmentHistory SELECT * FROM History |
注意:如果其他人準備使用同義詞,則管理員或所有者必須為其授予權限。針對視圖、表或表值函數,可對同義詞應用GRANT SELECT。針對過程或標量函數,可對同義詞應用 GRANT EXECUTE,諸如此類。
也可通過以下代碼,為完整的四部分名稱定義“History”同義詞:
CREATE SYNONYM History |
假設當前的用戶擁有使用同義詞的權限以及讀取表的權限,則使用類似的四部分全名即可在其他數據庫上下文中使用同義詞:
USE pubs |
還要注意,如果不提供架構名稱作為新同義詞名稱的一部分,它將成為默認架構的一部分。
【編輯推薦】

















