在進行許可權管理時,應遵守“最低許可權”原則,即每個人只授予必需的最小許可權。相對於授予的許可權,資料庫中還有一個特殊的許可權,那就是所有權(Ownship)。
SQL Server 用於管理許可權的TSQL命令有:GRANT用於授予許可權,REVOKE 用於移除已經被GRANT/DENY的許可權,而DENY用於防止安全主體通過GRANT獲得許可權。DENY一旦執行,Principal在Securable上的許可權就被禁用了。但是,SQL Server的許可權空間不是扁平的,是立體的,在不同的安全上下文(Security context)中,不同的許可權空間(Permission Space)中,這三個命令的優先順序是不同的。這就意味著,即使執行GRANT授予許可權,使用者不一定有許可權,這是因為在特定的許可權空間裡,Deny命令禁用了使用者的許可權,同時Grant命令的優先順序低於Deny。
一,管理許可權的規則
在管理許可權時,要注意許可權的上下文、許可權的立體空間和許可權的優先順序
1,安全上下文和許可權空間
安全上下文(Security Context),是跟user 或 login 相關的環境,使用者可以通過EXECUTE AS 來切換安全上下文。安全上下文主要包括:Login、User、Role membership、Windows Group membership
許可權空間,是指安全物件(Securable)和包含安全物件的所有安全物件類(Securable class),比如,表包含在schema 中,schema是表的安全物件類;而database包含schema,database是schema的安全物件類。訪問表的許可權,受到表、schema和database的許可權的影響,這三個物件構成一個許可權空間,訪問受到許可權空間的約束。
2,許可權的優先順序
當這三個命令作用於同一個安全物件(Securable)時,情況會變得複雜,不僅需要考慮許可權空間,還需要考慮許可權的優先順序。
- 在同一個安全主體範圍內對同一個安全物件設定許可權,GRANT子句會移除DENY和REVOKE子句設定的許可權,這三個命令的優先順序相同,後執行的語句會移除先執行語句的效果。
- 但是,當相同的許可權作用於同一安全主體的不同範圍時,如果DENY 作用於更高的範圍內,那麼DENY優先,但是在更高的範圍內,REVOKE不優先。
- 這裡有一個例外,列級別的GRANT語句,會覆蓋Object級別的DENY語句,但是後續Object級別的DENY語句會覆蓋列級別的GRANT語句。
許可權是累積的,一個User可以通過多種途徑(比如Grant、Role和Group memberhsip)來獲得授權,Revoke只能回收某一個途徑上的許可權,但是Deny會禁止使用者獲得授權。
舉個例子,一個User通過Grant獲得表1的SELECT許可權,通過Role獲得表1的SELECT許可權:
- 情況1:當使用REVOKE命令回收GRANT授予的SELECT 許可權時,該User仍然可以通過Role的許可權來查詢表1。
- 情況2:當使用DENY命令拒絕表1的許可權時,該User沒有許可權查詢表1。
3,許可權的層次結構
許可權的層次結構是一種父子結構,擁有父級別物件的許可權,預設擁有所有子級別物件的許可權。舉個例子,如果有資料庫級別的SELECT許可權,那麼就有了資料庫下所有Schema的SELECT許可權;如果有Schema的SELECT許可權,那麼就有了Schema下所有物件的SELECT許可權,這種許可權的結構構成許可權空間。
許可權是一個覆蓋式的許可權,舉個例子,Control表示所有的許可權,當對一個物件授予Control許可權,意味著授予所有其他的許可權。
資料庫級別的許可權:
- 在資料庫級別授予運算元據庫物件的許可權,比如 EXECUTE、DELETE、INSERT、SELECT、UPDATE、REFERENCES、VIEW DEFINITION,實際上,授予的是運算元據庫中所有物件的許可權。
- 資料庫級別獨有的許可權:ALTER、BACKUP DATABASE、BACKUP LOG、CHECKPOINT、CONNECT、CREATE TABLE、CREATE VIEW、CREATE PROCEDURE等
二,許可權管理的實現
許可權管理涉及到Principal、Securable和Permission三個概念。Principal可以是單個User,也可以是多個User構成的Windows Group;Securable可以是單個資料庫物件,也可以是包含多個資料庫物件的schema;同時,User也可以通過role獲得資料庫物件的許可權。
第一種方式,為每一個User設定單個Securable的許可權
第二種方式,建立Windows Group,把User分組,為每一個Windows Group設定單個Securable的許可權,簡少了授權使用者的數量。
第三種方式,通過資料庫 role來設定許可權,通過Role來組織Securable,減少了授權物件的數量。
第四種方式,通過Schema來設定許可權,在一個Schema下包含多個Securables,並通過Role來管理Scurable,通過Windows Group來管理User,這種方式雖然複雜,但是許可權的管理非常精細和靈活。
三,所有權和所有權鏈
物件的所有者對一個物件擁有所有可能的許可權,並且這些許可權不能禁止。CONTROL許可權可以執行與物件所有者幾乎相同的操作,但是所有權和授權是不同的。物件的所有者通常是其建立者,但是可以在建立時使用AUTHORIZATION子句指定其他所有者,也可以把Ownship轉移給其他Principal。
如何在不授予基礎表訪問許可權的情況下,僅對檢視或任何其他型別的程式授予SELECT許可權呢?答案是使用所有權鏈(Ownership-chaining)。通常情況下,當使用者從檢視中查詢資料時,系統做兩次許可權檢查,第一次是檢查使用者是否有許可權查詢檢視,第二次是在檢視引用基礎表時檢查使用者是否有許可權查詢基礎表,由於使用者沒有基礎表的許可權,因此第二次許可權檢查失敗。
所有權鏈(Ownership-chaining)通過繞過第二次許可權檢查來避免這種情況,否則將在檢視引用基礎表時進行第二次許可權檢查。當連結的物件(underlying table)與呼叫物件(view)具有相同的所有者時,許可權檢查將被完全繞開。
如果一個user在具有Ownership許可權的Schema中建立檢視,因為它檢視的所有者,就是被檢視引用的基表的所有者,這是一個鏈:我是Schema的所有者,那麼Schema下的所有物件的Owner都是我,我有許可權訪問檢視,但不能訪問基礎表。
所有權鏈只適用於SELECT, INSERT, DELETE, UPDATE 和MERGE,以及 SP和函式的EXECUTE 許可權,出於安全考慮,不適用於使用動態SQL的程式中。要在SP、函式和觸發器中執行動態SQL操作,需要使用使用WITH EXECUTE AS子句使用許可權模擬。只要呼叫者對動態SQL中引用的資料庫物件沒有許可權,就可以使用此EXECUTE AS子句,但要格外小心。它通過將執行上下文切換到模擬使用者來實現。所有程式碼,甚至是巢狀模組,都將在模擬使用者的安全上下文中執行。當前正在執行的批處理在執行程式碼時會臨時獲得例程所有者的許可權,而不是所有者的身份。這樣,使用者只能通過更改正在執行的程式碼來將特權用於任何其他目的。僅在過程執行完成後或在REVERT語句上,執行上下文才還原為原始呼叫方。
所有權鏈的問題在於,除了第一次許可權檢查之外,所有權連結會完全繞過許可權檢查,甚至都優先於DENY ACCESS。
參考文件:
Getting Started with Database Engine Permissions