在操作系统中,资源(如文件和注册表键,以及命名管道的句柄)都使用访问控制列表(ACL)来保护。下图显示了这个映射的结构。资源有一个关联的安全描述符。安全描述符包含了资源拥有者的信息,并引用了两个访问控制列表:自由访问控制列表(Discretionary Access Control List,DACL)和系统访问控制列表(System Access Control List,SACL)。DACL用来确定谁有访问权;SACL用来确定安全事件日志的审核规则。ACL包含一个访问控制项(Access Control Entries,ACE)列表。ACE包含类型、安全标识符和权限。在DACL中,ACE的类型可以是允许访问或拒绝访问。可以用文件设置和获得的权限是创建、读取、写入、删除、修改、改变许可和获得拥有权。
读取和修改访问控制的类在System.Security.AccessControl名称空间中。下面的程序说明了如何从文件中读取访问控制列表。
FileAccessControl实例应用程序使用了如下依赖项和名称空间:
依赖项
System.IO.FileSystem
System.IO.FileSystem.AccessControl
名称空间
System
System.IO
System.Security.AccessControl
System.Security.Principal
警告:
访问控制API只能用于Windows,不能用于Linux或Mac。System.IO.FileSystem.AccessControl API是Windows上资源管理的一部分。
FileStrem类定义了GetAccessControl()方法,该方法返回一个FileSecurity对象。FileSecurity是一个.NET类,它表示文件的安全描述符。FileSecurity类派生自基类ObjectSecurity、CommonObjectSecurity、NativeObjectSecurity和FileSystemSecurity。其他表示安全描述符的类有CryptoKeySecurity、EventWaitHandleSecurity、MutexSecurity、RegistrySecurity、SemaphoreSecurity、PipeSecurity和ActiveDirectorySecurity。所有这些对象都可以使用访问控制列表来保护。一般情况下,对应的.NET类定义了GetAccessControl()方法,返回相应的安全类;例如,Mutex.GetAccessControl()方法返回一个MutexSecurity类,PipeStream.GetAccessControl()方法返回一个PipeSecurity类。
FileSecurity类定义了读取、修改DACL和SACL的方法。GetAccessRules()方法以AuthorizationRuleCollection类的形式返回DACL。要访问SACL,可以使用GetAuditRules方法。
在GetAccessRules()方法中,可以确定是否应使用继承的访问规则(不仅仅使用对象直接定义的访问规则)。最后一个参数定义了应返回的安全标识符的类型。这个类型必须派生自基类IdentityReference。可能的类型有NTAccout和SecurityIdentifier。这两个类都表示用户或组。NTAccout类按名称查找安全对象,SecurityIdentifier类按唯一的安全标识符查找安全对象。
返回的AuthorizationRuleCollection包含AuthorizationRule对象。AuthorizationRule对象是ACE的.NET表示。在这里的例子中,因为访问一个文件,所以AuthorizationRule对象可以强制转换为FileSystemAccessRule类型。在其他资源的ACE中,存在不同的.NET表示,例如MutexAccessRule和PipeAccessRule。在FileSystemAccessRule类中,AccessControlType、FileSystemRights和IdentityReference属性返回ACE的相关信息:
class Program
{
static void Main(string[] args)
{
string fileName = null;
//if (args.Length == 0)
//{
// return;
//}
//fileName = args[0];
fileName = @"C:\Users\singh\Desktop\appsettings.txt";
using (FileStream stream = File.Open(fileName,FileMode.Open))
{
FileSecurity securityDescriptor = stream.GetAccessControl();
AuthorizationRuleCollection rules = securityDescriptor.GetAccessRules(true,true,typeof(NTAccount));
foreach (AuthorizationRule rule in rules)
{
var fileRule = rule as FileSystemAccessRule;
Console.WriteLine($"Access type: {fileRule.AccessControlType}");
Console.WriteLine($"Rights: {fileRule.FileSystemRights}");
Console.WriteLine($"Identity: {fileRule.IdentityReference.Value}");
Console.WriteLine();
}
}
}
}
运行应用程序,并传递一个文件名,就可以看到文件的访问控制列表。这里的输出列出了管理员和系统的全部控制权限、通过身份验证的用户的修改权限,以及属于Users组的所有用户的读取和执行权限。
Access type: Allow
Rights: FullControl
Identity: NT AUTHORITY\SYSTEM
Access type: Allow
Rights: FullControl
Identity: BUILTIN\Administrators
Access type: Allow
Rights: FullControl
Identity: DESKTOP-EUK91RH\singh
设置访问权限非常类似于读取访问权限。要设置访问权限,几个可以得到保护的资源类提供了SetAccessControl()和ModifyControl()方法。这里的示例代码调用给FileInfo类定义的SetAccessControl()扩展方法,以修改文件的访问控制列表。给这个方法传递一个FileSecurity对象。FileSecurity对象用FileSystemAccessRule对象填充。这里列出的访问规则拒绝Sales组的写入访问权限,给Everyone组提供了读取访问权限,并给Developers组提供了全部控制权限。
注意:
只有定义了Windows组Sales和Developers以及Everyone,这个程序才能在系统上运行。可以修改程序,使用自己环境下的可用组。
private static void WriteAcl(string fileName)
{
//使用自己的用户组:Guests、Device Owners、Users
var guestsIdentity = new NTAccount("Guests");
var deviceOwnersIdentity = new NTAccount("Device Owners");
var usersIdentity = new NTAccount("Users");
var guestsAce = new FileSystemAccessRule(guestsIdentity,FileSystemRights.Write,AccessControlType.Deny);
var usersAce = new FileSystemAccessRule(usersIdentity,FileSystemRights.Read,AccessControlType.Allow);
var deviceOwnersAce = new FileSystemAccessRule(deviceOwnersIdentity,FileSystemRights.FullControl,AccessControlType.Allow);
var securityDescriptor = new FileSecurity();
securityDescriptor.SetAccessRule(guestsAce);
securityDescriptor.SetAccessRule(usersAce);
securityDescriptor.SetAccessRule(deviceOwnersAce);
//using (var stream = new FileStream(fileName, FileMode.Open))//会出现异常: UnauthorizedAccessException
//{
// try
// {
// stream.SetAccessControl(securityDescriptor);
// }
// catch (UnauthorizedAccessException ex)
// {
// Console.WriteLine(ex.Message);
// }
//}
FileInfo file = new FileInfo(fileName);
file.SetAccessControl(securityDescriptor);
}
注意:
打开该文件属性窗口,在安全选项卡,列出了改变后的访问控制列表,可以验证访问规则。