存取控制清單 (Access Control List, ACL)
前一章節中,我們透過 RBS 架構下的驗證與授權機制 (Principal Permission),達到限制特定使用者或群組對程式碼的存取。
存取控制清單 (ACL) 也是一種權限控管的機制,是作業系統用來管控資源的使用權限檔案,如:資料夾、印表機、註冊機碼等。 它是由存取控制項 (ACE) 所組成,每一項 ACE 指明了某物件是否可被存取。 例如,若想阻止系統管理員以外的任何人讀取某個檔案,就可以建立一個特定的 ACE,並套用到該檔案的存取控制清單 (ACL) 即可。
ACL 包含二種類型:
- discretionary access control list (DACL):自主式存取控制清單
- system access control list (SACL):系統存取控制清單
自主式存取控制清單 ( Discretionary Access Control List, DACL )
什麼是自主式存取控制清單(Discretionary Access Control List, DACL)
自主式存取控制 (DAC) 是一種針對使用者或群組,允許或拒絕他們存取資源的一種機制。 它使用存取控制項 (ACE) 來判斷使用者或群組的存取權限。 例如,若想阻止系統管理員以外的任何人讀取某個檔案,就可以建立一個特定的 ACE,並套用到該檔案的存取控制清單 (ACL) 即可。
在 Windows 作業系統裡,每一個系統物件都擁有自己的 ACL 權限表, 以 NTFS 檔案系統內的檔案來說好了,每個檔案都有六種基本權限:Full Control、Modify、Read&Execute、Read、Write、特殊權限。 而在 [進階] 選項中,還能更進一步的設定檔案的所有權限,包含檔案的 7 種延伸權限,故檔案的權限設定總共有 13 種,如下圖:。
DACL 的管控機制
若將使用者看成主體(subject),檔案或資源看成客體(object)。 那麼 RBS 機制就是將權限管制表記錄在主體身上,而 DACL 則是將權限管制表記錄在客體身上。
這個管制表就稱為存取控制清單 (ACL),而清單內則是由存取控制項 (ACE) 所組成,每一項 ACE 指明了某物件是否可被存取(如圖)。 當 Process 想要存取一個受保護的物件,系統會先檢查該物件的 DACL 中的 ACEs 項目,以決定是否授與 Process 的存取權限。 若該物件沒有 DACL,系統就會授與任何人完整的存取權限。 若該物件有 DACL,卻不含任何 ACEs,系統則會禁止任何人的存取。
如 Alice 和 Bob 擁有資料庫之存取權限,在資料庫維護存取控管清單上,Alice 僅有讀取權限,Bob 則擁有讀取、寫入、修改與刪除權限。
系統如何計算有效的使用權限
明確的與繼承的使用權限
在指派使用權限給物件時,有二種方法
- 明確指派:(Explicit Permissions)
當指派 DACL 給一個物件時,就是在建立一個明確的使用限權。例如,指派明確的使用權限給每個檔案、資料夾、登錄機碼。 - 繼承指派:(Inherited Permissions)
繼承的使用權限比明確指派有效率多了。它使用尤其父層物件傳播下來的權限。 有了這樣子的機制,在建立新物件時,就不需要明確指定使用權限。新的物件會繼承其父層的使用權限。
使用權限是累積的
授與一個使用者或所屬群組的使用權限是用累積(sumulative)的概念的。 例如,使用者vito,同時為 IT 和 Managers 群組的成員, 若某一個檔案的 ACL 給 vito 只有 Read 權限,給 IT 群組 Modify 權限,給 Managers 群組 Full Control 權限。 如此一來,vito將有 Full Control 權限。
拒絕權限永遠覆寫授與權限
在多個 ACL 中,若有一個是拒絕存取用的 ACL,那麼它將覆寫授與存取權限的 ACL。 如上例中,若 IT 群組明確的被拒絕存取,即使 vito 為 Managers 群組的成員,且該群組有 Full Control 權限,vito 也無法存取該檔案。
系統存取控制清單 ( System Access Control List, SACL )
系統存取控制清單 (SACL),有時也稱為稽核 ACE,它讓系統管理員可以記錄誰嘗試存取安全性物件。 SACL 與 DACL 類似,它們都是使用 ACE 來定義特定資源的存取規則。 但是與 DACL 不同的是,它不會限制資源的存取,而是當使用者嘗試存取資源時,會產生事件記錄,並記載到 Windows 事件記錄中的安全性類別。
不過,預設上,即使指派了 SACL 給資源,Windows 也是不會記錄稽核事件的。它必須還得啟動物件的存取稽核原則才行。該項設定位於本機安全性原則管理工具裡頭。如下圖:
double-click 稽核物件,勾選失敗,可啟動失敗稽核,勾選成功,可啟動成功稽核。
如何檢視與設定組件中的 ACLs
有哪些資源提供 ACL 存取
.NET Framework 提供下列資源 ACL 的存取,所有資源的存取控制項目都定義在 System.Security.AccessControl 命名空間。 雖然所有資源都有存取控制清單,但不同資源使用的是不一樣的存取控制清單。
此外,每一種資源型別各有三種不同功能的 ACL 類別:
ObjectSecurity:安全性類別。這個類別封裝了 DACL 和 SACL 類別。
所有的安全性類別都是繼承自 NativeObjectSecurity
- DirectorySecurity :表示目錄的存取控制和稽核安全性。
- FileSecurity :表示檔案的存取控制和稽核安全性。
- RegistrySecurity :表示登錄機碼的 Windows 存取控制 (Access Control) 安全性。
- CryptoKeySecurity :提供無需直接管理存取控制清單 (ACL),即可控制對密碼編譯金鑰物件之存取的功能。
- EventWaitHandleSecurity :表示套用至具名系統等候控制代碼 (Wait Handle) 的 Windows 存取控制安全性。
- MutexSecurity :表示具名 Mutex 的 Windows 存取控制安全性。
- SemaphoreSecurity :表示具名號誌 (Semaphore) 的 Windows 存取控制安全性。
ObjectAccessRule:存取規則類別。
封裝 ACE 的類別。它們都是繼承自 AccessRule ,而 AccessRule 繼承自 AuthorizationRule 。
- FileSystemAccessRule :表示檔案或目錄的存取規則。
- RegistryAccessRule :表示登錄機碼的存取規則。
- CryptoKeyAccessRule :表示密碼編譯金鑰的存取規則
- EventWaitHandleAccessRule :表示檔案或目錄的存取規則。
- MutexAccessRule :表示具名 Mutex 的存取規則。
- SemaphoreAccessRule :表示具名號誌的存取規則。
ObjectAuditRule:稽核規則類別。
封裝 Audit ACE 的類別。它們也都是繼承自 AuditRule ,而 AuditRule 繼承自 AuthorizationRule 。
.NET Framework 中的 ACEs
同樣的,雖然各種 ACL 都是由 ACE 組成,但不同資源的 ACE 當然也就不一樣。 例如,雖然檔案系統和登錄資料庫都有 Full Control 和 Delete 使用權限,但 Read&Execute 僅用於檔案和資料夾,而 Query Value 僅用於登錄資料庫。 所以,每個資源都有其專用的類別,不同資源各自的使用權限與功能都類似,且所有類別皆繼承自共同的基底的類別。例如:
- FileSystemRights :這個列舉型別用來指定檔案和資料夾的使用權限。
- RegistryRights :這個列舉型別用來指定登錄資料庫的使用權限。
- CryptoKeyRights :指定授權規則控制存取或稽核的密碼編譯金鑰作業。
- EventWaitHandleRights :指定可套用至具名系統事件物件的存取控制 (Access Control) 權限。
- MutexRights :指定可套用至具名系統 Mutex 物件的存取控制權限。
- SemaphoreRights :指定可套用至具名系統號誌 (Semaphore) 物件的存取控制 (Access Control) 權限。
與 ACE 相關的列舉型別:
AccessControlType
指定 AccessRule 物件是用於允許存取還是拒絕存取。這些值不是旗標,它們也不可組合。
- Allow:允許存取 secured object。
- Deny:禁止存取 secured object。
AccessControlSections
指定要儲存或載入的安全性描述元 (Security Descriptor) 區段。這個列舉值不可組合使用。
- None :沒有區段。
- Audit :系統存取控制清單 (SACL)。
- Access :自主式存取控制清單 (DACL)。
- Owner :擁有人。
- Group :主要群組。
- All :整個安全性描述元。
FileSystemRights
定義檔案或目錄建立存取規則和稽核規則時要使用的存取權限。這個列舉值可組合使用。
- FullControl :
- Read :
- Write :
- Modify :
- Delete :
- ReadAndExecute :
- ListDirectory :
- Other members :
AuditFlags
稽核嘗試存取安全物件的條件。這個列舉值可組合使用。
- None :不稽核
- Success :稽核成功的存取嘗試。
- Failure :稽核失敗的存取嘗試
牛刀小試
若要針對檔案系統設定 ACL ,大至步驟如下:
- 建立 FileSecurity 檔案安全性類別的執行個體
- 使用 FileSystemAccessRule 類別建立存取規則
或使用 FileSystemAuditRule 類別建立稽核規則 - 使用 FileSystemRights 列舉型別設定權限
- 叫用 File.SetAccessControl 方法,套用權限設定
string fileName = "test.xml"; string account=".\vito"; FileSystemRights rights; AccessControlType controlType; rights = FileSystemRights.ReadData; controlType = AccessControlType.Allow; //===================================================== // 建立檔案的 ACL //===================================================== FileSecurity fSecurity = File.GetAccessControl(fileName); FileSystemAccessRule fAccessRule = new FileSystemAccessRule(account, rights, controlType); //===================================================== // 加入存取規則,並套用至指定的檔案 //===================================================== // 在 ACL 中加入存取規則 fSecurity.AddAccessRule(fAccessRule); // 套用至指定的檔案 File.SetAccessControl(fileName, fSecurity); //===================================================== // 移除存取規則,並套用至指定的檔案 //===================================================== // 移除在 ACL 中的存取規則 fSecurity.RemoveAccessRule(fAccessRule); // 套用至指定的檔案 File.SetAccessControl(fileName, fSecurity);
下面範例示範如何建立登錄資料庫的存取規則和稽核規則:
FileSecurity File_Security = new FileSecurity(); FileSystemAccessRule Access_Rule = new FileSystemAccessRule("vito", FileSystemRights.Read, AccessControlType.Allow); FileSystemAuditRule Audit_Rule = new FileSystemAuditRule("vito", FileSystemRights.Read, AuditFlags.Failure); MutexSecurity Mutex_Security = new MutexSecurity(); MutexAccessRule Mutex_AccessRule = new MutexAccessRule("vito", MutexRights.FullControl, AccessControlType.Allow); MutexAuditRule Mutex_AuditRule = new MutexAuditRule(new NTAccount("vito"), MutexRights.Delete, AuditFlags.Success); RegistrySecurity Registry_Security = new RegistrySecurity(); RegistryAccessRule Registry_AccessRule = new RegistryAccessRule("vito", RegistryRights.FullControl, AccessControlType.Allow); RegistryAuditRule Registry_AuditRule = new RegistryAuditRule(new NTAccount("vito"), RegistryRights.Delete, InheritanceFlags.ContainerInherit, PropagationFlags.NoPropagateInherit,AuditFlags.Success);
如何讀取資源的 ACLs
讀取 DACL
若要取得資源的 ACLs ,可依照下列步驟:
- 建立 NativeObjectSecurity 衍生類別的執行個體,如 DirectorySecurity 、 FileSecurity 。
要建立 NativeObjectSecurity 衍生類別的執行個體,除了建立 <ResourceObject>Security 類別外,通常也可以由相關類別中的 GetAccessControl 方法取得。例如:
- RegistryKey.GetAccessControl :傳回目前登錄機碼的存取控制安全性。
- Directory.GetAccessControl :擷取目錄的存取控制清單 (ACL) 項目。
- File.GetAccessControl :擷取指定檔案的存取控制清單 (ACL) 項目。
- 呼叫執行個體的 GetAccessRules 方法以取得存取規則的集合( AuthorizationRuleCollection ) 。
- 逐一檢查 AuthorizationRuleCollection 中的項目,以分析每個 ACL。
雖然用來取得 ACL 物件的類別不盡相同,但方法是相同的。不過要注意,每一種 ACL 物件的 GetAccessRules 方法,回傳的集合,其內含項目是不同的。例如:
- RegistrySecurity.GetAccessRules : 回傳包含 RegistryAccessRule 的 AuthorizationRuleCollection 。
- DirectorySecurity.GetAccessRules : 回傳包含 FileSystemAccessRule 的 AuthorizationRuleCollection 。
取得檔案的存取控制清單: File.GetAccessControl
public static FileSecurity GetAccessControl(string path); public static FileSecurity GetAccessControl(string path, AccessControlSections includeSections);
取得目錄的存取控制清單: Directory.GetAccessControl
public static DirectorySecurity GetAccessControl(string path); public static DirectorySecurity GetAccessControl(string path, AccessControlSections includeSections);
取得與指定之安全識別項相關聯的存取規則集合: GetAccessRules
public AuthorizationRuleCollection GetAccessRules(bool includeExplicit, bool includeInherited, Type targetType);
// 1) 建立 NativeObjectSecurity 衍生類別的執行個體 DirectorySecurity dSecurity = new DirectorySecurity(@"C:\Program Files", AccessControlSections.Access); // 1) 透過 Directory.GetAccessControl 也可以取得相同執行個體 DirectorySecurity dSecurity2 = Directory.GetAccessControl(@"C:\Program Files", AccessControlSections.Access); // 2) 呼叫 GetAccessRules 方法,以取得 AuthorizationRuleCollection AuthorizationRuleCollection accessRules = dSecurity.GetAccessRules(true, true, typeof(NTAccount)); // 3) 逐一檢查 AuthorizationRuleCollection 執行個體中的項目 foreach (FileSystemAccessRule accessRule in accessRules) Console.WriteLine(accessRule.IdentityReference + ": " + accessRule.AccessControlType + " " + accessRule.FileSystemRights); //CREATOR OWNER : Allow 268435456 //NT AUTHORITY\SYSTEM : Allow 268435456 //NT AUTHORITY\SYSTEM : Allow Modify, Synchronize //BUILTIN\Administrators : Allow 268435456 //BUILTIN\Administrators : Allow Modify, Synchronize //BUILTIN\Users : Allow -1610612736 //BUILTIN\Users : Allow ReadAndExecute, Synchronize //NT SERVICE\TrustedInstaller : Allow 268435456 //NT SERVICE\TrustedInstaller : Allow FullControl // 底下方法可以用來驗證特定使用者的存取權限 string NtAccountName = "VITO-2011W7\\vito"; foreach (FileSystemAccessRule rule in accessRules) { if (rule.IdentityReference.Value.Equals(NtAccountName, StringComparison.CurrentCultureIgnoreCase)) { if ((rule.FileSystemRights & FileSystemRights.WriteData) > 0) { Console.WriteLine("{0} has WriteData permission to {1}", NtAccountName, dir); } if ((rule.FileSystemRights & FileSystemRights.ReadAndExecute) > 0) { Console.WriteLine("{0} has ReadAndExecute permission to {1}", NtAccountName, dir); } if ((rule.FileSystemRights & FileSystemRights.Delete) > 0) { Console.WriteLine("{0} has Delete permission to {1}", NtAccountName, dir); } } }
// 1) 建立 NativeObjectSecurity 衍生類別的執行個體 RegistrySecurity rs = Registry.LocalMachine.GetAccessControl(); // 2) 呼叫 GetAccessRules 方法,以取得 AuthorizationRuleCollection AuthorizationRuleCollection arc = rs.GetAccessRules(true, true, typeof(NTAccount)); // 3) 逐一檢查 AuthorizationRuleCollection 執行個體中的項目 foreach (RegistryAccessRule ar in arc) Console.WriteLine(ar.IdentityReference + ": " + ar.AccessControlType + " " + ar.RegistryRights); //Everyone : Allow ReadKey //NT AUTHORITY\RESTRICTED : Allow ReadKey //NT AUTHORITY\SYSTEM : Allow FullControl //BUILTIN\Administrators : Allow FullControl
讀取 SACL
若要分析 SACLs ,可使用相同步驟,但呼叫 GetAuditRules 來替換 GetAccessRules 。
// 1) 建立 NativeObjectSecurity 衍生類別的執行個體 DirectorySecurity dSecurity = new DirectorySecurity(@"C:\Program Files", AccessControlSections.Access); // 1) 透過 Directory.GetAccessControl 也可以取得相同執行個體 DirectorySecurity dSecurity2 = Directory.GetAccessControl(@"C:\Program Files", AccessControlSections.Access); // 2) 呼叫 GetAccessRules 方法,以取得 AuthorizationRuleCollection AuthorizationRuleCollection accessRules = dSecurity.GetAuditRules(true, true, typeof(NTAccount)); // 3) 逐一檢查 AuthorizationRuleCollection 執行個體中的項目 foreach (FileSystemAccessRule accessRule in accessRules) Console.WriteLine(accessRule.IdentityReference + ": " + accessRule.AccessControlType + " " + accessRule.FileSystemRights);
如何設定 ACLs
使用 SetAccessControl
SetAccessControl 是用來將 ACLs 套用至指定的物件上。若要設定 ACLs ,可依照下列步驟:
- 1. 呼叫 GetAccessControl 方法以取得 NativeObjectSecurity 衍生類別的執行個體,如 DirectorySecurity 、 FileSecurity 。
- 2. 加入或移除 ACL 項目。
- 3. 呼叫 SetAccessControl 方法執行寫入作業。
同樣的,因為資源不同,就必須使用不同的控制存取安全物件,
//File 的 SetAccessControl public static void SetAccessControl(string path, FileSecurity fileSecurity); //Directory 的 SetAccessControl public static void SetAccessControl(string path, DirectorySecurity directorySecurity);
string dir1 = @"C:\temp\sub1"; string account = "vito"; FileSystemRights rights = FileSystemRights.DeleteSubdirectoriesAndFiles | FileSystemRights.FullControl; AccessControlType rule = AccessControlType.Allow; // 1)加入安全性 DirectorySecurity dirSecurity1 = Directory.GetAccessControl(dir1); //取得目前現有安全性 dirSecurity1.AddAccessRule(new FileSystemAccessRule(account, rights, rule)); //加入安全性 Directory.SetAccessControl(dir1, dirSecurity1); //套用新的安全性 // 2)移除安全性 DirectorySecurity dirSecurity2 = Directory.GetAccessControl(dir1); dirSecurity2.RemoveAccessRule(new FileSystemAccessRule(account, rights, rule)); // 移除 AccessRule 規則 Directory.SetAccessControl(dir1, dirSecurity2); // 套用規則 // 3)新設安全性 string dir2 = @"C:\temp\sub2"; DirectorySecurity dirSecurity3 = new DirectorySecurity(); dirSecurity3.AddAccessRule(new FileSystemAccessRule(account, rights, rule)); if (!Directory.Exists(dir2)) Directory.CreateDirectory(dir2, dirSecurity3); else Directory.SetAccessControl(dir2, dirSecurity3);
使用 SetAccessRuleProtection
當我們使用 File 或 Directory 的時候,它們的存取權限預設都會繼承父項物件。 這個情況包含變更父項物件的存取權限時,其子物件的存取權限預設會因為繼承特性而自動跟著變更。 或者當我們將某個子目錄移動到另一個目錄之下,這個子目錄的存取權限,也會因為繼承特性而自動跟著變更。
SetAccessRuleProtection 這個方法就是用來設定或移除與這個 ObjectSecurity 物件相關聯的存取規則保護。
SetAccessRuleProtection(bool isProtected, bool preserveInheritance);
- isProtected:true 表示使用目前物件的存取規則,不因繼承而改變;false 表示允許因繼承而變更存取規則。
- preserveInheritance:true 表示保留繼承的存取規則,而 false 則表示移除繼承的存取規則。如果 isProtected 為 false,則忽略這個參數。
下面這個例子,我們套用 dir1 的存取權限到新建立的 dir2 身上,並將 dir2 的 ACL 設定成保護。 這樣子,不管將來 dir2 上層的權限如何變更,或被搬移到哪個目錄之下,它的存取權限都不會因為繼承而被變更。
string dir1 = @"C:\temp\test1"; string dir2 = @"C:\temp\test2"; DirectorySecurity dirSecurity = Directory.GetAccessControl(dir1, AccessControlSections.All); bool isProtected = true; bool isPreserved = true; dirSecurity.SetAccessRuleProtection(isProtected, isPreserved); Directory.CreateDirectory(dir2, dirSecurity);
沒有留言:
張貼留言