【windows 访问控制】十一、C# 实操 对象 System.Security.AccessControl 命名空间
AccessControl 命名空间 结构图
解说:
DirectorySecurity=目录ACL
FileSecurity=文件ACL
FileSystemAuditRule=目录和文件中SACL中的ACE
FileSystemAccessRule=目录和文件中DACL中的ACE
GetAccessControl=ACL(AccessControlList)The security descriptors of all the access control sections of the directory.
DirectorySecurity类和FileSecurity类是对基础Microsoft Windows文件安全系统的抽象。----注:本文部分内容改编自《.NET安全揭秘》
FileSystemAccessRule和FileSystemAuditRule 类是对组成DACL和SACL的访问控制项(ACE)的抽象----注:本文部分内容改编自《.NET安全揭秘》
案例1、window平台的ACL、 ACE操作实例
給文件夹添加访问控制项(ACE:), 要以管理员的方式运行vs2022,这样才能正确的添加sACE,特权。
新建一个ACL
第一方式,新建一个ACL,然后赋值给文件,这种方式会覆盖原来ACL的列表。并且对文件的sACE,dACE经行增删改
using System.Diagnostics; using System.Security.AccessControl; using System.Security.Principal; //把桌面设置未当前目录 Directory.SetCurrentDirectory(Environment.GetFolderPath(Environment.SpecialFolder.Desktop )); //用n #region 添加ACE //新建ACE ,ACE FileSystemAuditRule SACE = new("TestAccount", FileSystemRights.FullControl, AuditFlags.Success); FileSystemAuditRule SACE2 = new(WindowsIdentity.GetCurrent().Name, FileSystemRights.Read, AuditFlags.Failure); FileSystemAuditRule SACE3 = new("TestAccount", FileSystemRights.Modify, AuditFlags.Failure); FileSystemAccessRule DACE = new("TestAccount" ,FileSystemRights.FullControl,AccessControlType.Deny); FileSystemAccessRule DACE2 = new(WindowsIdentity.GetCurrent().Name, FileSystemRights.Read|FileSystemRights.Write,InheritanceFlags.None,PropagationFlags.None, AccessControlType.Allow); FileSystemAccessRule DACE3 = new("TestAccount", FileSystemRights.Read , AccessControlType.Allow); //关联桌面的已经存在的CSD文件夹 DirectoryInfo dir = new ("CSD"); //获取文件的ACL DirectorySecurity ACL=dir.GetAccessControl(); //将sACEs、dACLs加入ACL ACL.AddAccessRule(DACE); ACL.AddAccessRule(DACE2); ACL.AddAccessRule(DACE3); ACL.AddAuditRule(SACE); ACL.AddAuditRule(SACE2); ACL.AddAuditRule(SACE3); dir.SetAccessControl(ACL); //获取文件夹SACL权限 DirectorySecurity AClwithAudit = dir.GetAccessControl(AccessControlSections.Audit); foreach (FileSystemAuditRule item in AClwithAudit.GetAuditRules(true, true, typeof(NTAccount))) { Console.WriteLine(item.AuditFlags); } Console.Read(); //获取文件夹DACL权限 DirectorySecurity AClwithAccess = dir.GetAccessControl(AccessControlSections.Access); foreach (FileSystemAccessRule item in AClwithAccess.GetAccessRules(true, true, typeof(NTAccount))) { Console.WriteLine(item.AccessControlType ); } #endregion //removeDACE("TestAccount","CSD",AccessControlType.Deny); RemoveAllDACE("TestAccount","CSD");
/// <summary> /// 删除指定用户的文件夹dACE /// </summary> static void RemovedDACE(string username,string fielname, AccessControlType Type) { DirectoryInfo dir = new (fielname); DirectorySecurity AClwithAccess = dir.GetAccessControl(AccessControlSections.Access); foreach (FileSystemAccessRule dace in AClwithAccess.GetAccessRules(true, true, typeof(NTAccount))) { Console.WriteLine(dace.IdentityReference.Value); if (dace.AccessControlType == Type && dace.IdentityReference.Value == @$"{Environment.UserDomainName}\{username}") { AClwithAccess.ModifyAccessRule(AccessControlModification.Remove, dace, out bool ivalue); if (ivalue == true) { dir.SetAccessControl(AClwithAccess); Console.WriteLine("移除成功"); } } } } /// <summary> /// 删除指定用户在指定文件夹的所有D-ACE权限 /// </summary> static void RemoveAllDACE(string username,string filename) { DirectoryInfo dir = new (filename); DirectorySecurity AClwithAccess = dir.GetAccessControl(); AClwithAccess.PurgeAccessRules(new NTAccount(@$"{Environment.UserDomainName}\{username}")); dir.SetAccessControl(AClwithAccess); Console.WriteLine("移除成功"); } /// <summary> /// 删除指定用户的文件夹sACE /// </summary> static void RemovedSACE(string username, string fielname, AuditFlags Type) { DirectoryInfo dir = new(fielname); DirectorySecurity AClwithAccess = dir.GetAccessControl(AccessControlSections.Access); foreach (FileSystemAuditRule sace in AClwithAccess.GetAuditRules(true, true, typeof(NTAccount))) { Console.WriteLine(sace.IdentityReference.Value); if (sace.AuditFlags == Type && sace.IdentityReference.Value == @$"{Environment.UserDomainName}\{username}") { AClwithAccess.ModifyAuditRule(AccessControlModification.Remove, sace, out bool ivalue); if (ivalue == true) { dir.SetAccessControl(AClwithAccess); Console.WriteLine("移除成功"); } } } } /// <summary> /// 删除指定用户在指定文件夹的所有S-ACE权限 /// </summary> static void RemovedALLSACE(string username, string filename) { DirectoryInfo dir = new(filename); DirectorySecurity AClwithAudit = dir.GetAccessControl(); AClwithAudit.PurgeAuditRules(new NTAccount(@$"{Environment.UserDomainName}\{username}")); dir.SetAccessControl(AClwithAudit); Console.WriteLine("移除成功"); }
下面详细的介绍一下比较重要的几个方法,第一个:
一、 public FileSystemAccessRule( string identity, FileSystemRights fileSystemRights, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AccessControlType type)
定义访问规则,参数如下:
identity
Type: System.String
The name of a user account. (账户名)
fileSystemRights
Type: System.Security.AccessControl.FileSystemRights
One of the FileSystemRights values that specifies the type of operation associated with the access rule. (与访问规则相关联的操作类型)
inheritanceFlags
Type: System.Security.AccessControl.InheritanceFlags
One of the InheritanceFlags values that specifies how access masks are propagated to child objects.
(CSDN上解释的是“该值指示如何将访问掩码传播到子对象”,我的理解是 该值规定是将继承规则作用在文件夹上还是文件上)
propagationFlags
Type: System.Security.AccessControl.PropagationFlags
One of the PropagationFlags values that specifies how Access Control Entries (ACEs) are propagated to child objects.
(CSDN上解释的是“该值指定如何将访问控制项 (Ace) 传播到子对象”,propagationFlags能起作用的前提是inheritanceFlags不为None)
type
Type: System.Security.AccessControl.AccessControlType
One of the AccessControlType values that specifies whether to allow or deny the operation.(允许还是拒绝)
第一个参数是账户名,第二个是操作类型,操作类型对应的有以下:
("AppendData", "附加数据");
("ChangePermissions", "更改权限");
("CreateDirectories", "创建文件夹/附加数据");
("CreateFiles", "创建文件/写入数据");
("Delete", "删除");
("DeleteSubdirectoriesAndFiles", "删除子文件夹及文件");
("ExecuteFile", "执行文件");
("FullControl", "完全控制");
("ListDirectory", "列出文件夹/读取数据");
("Modify", "修改");
("Read", "读取");
("ReadAndExecute", "读取和执行");
("ReadAttributes", "读取属性");
("ReadData", "读取数据");
("ReadExtendedAttributes", "读取扩展属性");
("ReadPermissions", "读取权限");
("Synchronize", "同步");
("TakeOwnership", "更改文件(夹)所有者");
("Traverse", "执行程序");
("Write", "写入");
("WriteAttributes", "写入属性");
("WriteData", "写入数据");
("WriteExtendedAttributes", "写入扩展属性");
第三四个参数比较难懂,并且他两个应该组合起来应用。一个是inheritanceFlags(ContainerInherit,None,ObjectInherit),另一个是propagationFlags(InheritOnly,None,NoPropagateInherit),这两枚举都有三个值,都具有允许其成员值的按位组合的 FlagsAttribute 特性,propagationFlags能起作用的前提是inheritanceFlags不为None。
下面是我总结的常用的枚举组合:
对应到windows界面操作上后,如下图所示:
第五个参数规定该访问规则的类型是 允许还是拒绝。
现有的ACL上添加ACE
using System.Security.AccessControl; using System.Security.Principal; //把桌面设置未当前目录 Directory.SetCurrentDirectory(Environment.GetFolderPath(Environment.SpecialFolder.Desktop )); //新建ACE ,ACE的拥有者设置成当前 操作系统用 FileSystemAuditRule SACE=new FileSystemAuditRule(WindowsIdentity.GetCurrent().Name,FileSystemRights.FullControl,AuditFlags.Success); FileSystemAccessRule DACE = new FileSystemAccessRule(WindowsIdentity.GetCurrent().Name,FileSystemRights.FullControl,AccessControlType.Deny); FileSystemAccessRule DACE2 = new FileSystemAccessRule(WindowsIdentity.GetCurrent().Name, FileSystemRights.Read|FileSystemRights.Write,InheritanceFlags.None,PropagationFlags.None, AccessControlType.Allow); //新建文件,并且ACL把文件添加到目录上。会和原来的ACL列表合并 DirectoryInfo dir = new DirectoryInfo("CSD"); DirectorySecurity sd=dir.GetAccessControl(); sd.AddAccessRule(DACE); sd.AddAccessRule(DACE2); dir.SetAccessControl(sd);
遍历ACL中的ACE
遍历ACL中的ACE AuthorizationRuleCollection rules = fileAcl.GetAccessRules(true, true, typeof(NTAccount)); // AuthorizationRule Rule = rules[0]; foreach (FileSystemAccessRule rule in rules) { if(rule.IdentityReference.Value.CompareTo("Users")==0) { fileAcl.RemoveAccessRule(rule); } }
文件夹权限继承控制
DirectorySecurity ss = di.GetAccessControl(); ss.SetAccessRuleProtection(true,true);//这个是保护acl,防止继承,true为启用保护,这样就不会继承父类了,第二项是否保留已经继承的。
获取ACE的掩码
using System.Security.AccessControl; using System.IO; using System.Security.Principal; using System.Reflection; Directory.SetCurrentDirectory(Environment.GetFolderPath(Environment.SpecialFolder.Desktop)); DirectoryInfo di = new("CSD"); DirectorySecurity ss = di.GetAccessControl(); Console.WriteLine(ss.GetGroup(typeof(NTAccount))); foreach (FileSystemAccessRule ace in ss.GetAccessRules(true,true,typeof(NTAccount))) { Type getMask = typeof(FileSystemAccessRule); PropertyInfo propertyInfo = getMask.GetProperty("AccessMask", BindingFlags.Instance|BindingFlags.NonPublic | BindingFlags.GetProperty); int Mask =int.Parse( propertyInfo.GetValue(ace, null).ToString()); Console.WriteLine($"AccessControltype:{ace.FileSystemRights} AcessMask:{ Convert.ToString(Mask, 2).PadLeft(32,'0') }"); }
案例2、通用平台的ACL ACE操作实例
这些方式是操作SD类型的通用方式(与底层的Windows资源的类型无关),.NET提供了如下类型:
- System.Security.AccessControl.GenericSecurityDescriptor
- System.Security.AccessControl.CommonSecurityDescriptor
- System.Security.AccessControl.RawSecurityDescriptor
- System.Security.AccessControl.GenericAcl
- System.Security.AccessControl.CommonAcl
- System.Security.AccessControl.DescretionaryAcl
- System.Security.AccessControl.SystemAcl
- System.Security.AccessControl.RawAcl
- System.Security.AccessControl.GenericAce
- System.Security.AccessControl.CustomAce
- System.Security.AccessControl.KnownAce
- System.Security.AccessControl.CompoundAce
- System.Security.AccessControl.QualifiedAce
- System.Security.AccessControl.CommonAce
- System.Security.AccessControl.ObjectAce
示例:创建一个SD,向其DACL中添加ACE并将其转化为一个代表Windows资源的特殊SD(此处为互斥体)。
using System; using System.Security.AccessControl; using System.Security.Principal; class Program { static void Main() { //创建一个新的SD CommonSecurityDescriptor csd = new CommonSecurityDescriptor(false, false, string.Empty); DiscretionaryAcl dacl = csd.DiscretionaryAcl; //向DACL中添加ACE dacl.AddAccess( AccessControlType.Allow, // 枚举Allow、Deny. WindowsIdentity.GetCurrent().Owner, (int)MutexRights.TakeOwnership | (int)MutexRights.Synchronize, InheritanceFlags.None, // 禁用ACE继承 PropagationFlags.None); string sSDDL = csd.GetSddlForm( AccessControlSections.Owner ); MutexSecurity mutexSec = new MutexSecurity(); mutexSec.SetSecurityDescriptorSddlForm( sSDDL ); AuthorizationRuleCollection aces = mutexSec.GetAccessRules(true, true, typeof(NTAccount)); foreach ( AuthorizationRule ace in aces ) { if (ace is MutexAccessRule) { MutexAccessRule mutexAce = (MutexAccessRule)ace; Console.WriteLine( "-->SID : " + mutexAce.IdentityReference.Value ); Console.WriteLine( "访问权限类型:" + mutexAce.AccessControlType.ToString()); if (0xffffffff == (uint) mutexAce.MutexRights) Console.WriteLine( "拥有所有权限" ); else Console.WriteLine( "权限: " + mutexAce.MutexRights.ToString()); } } } }