The Basics of Manipulating File Access Control Lists with C#
A familiar security saying goes: "A system is as secure as its weakest link." For example, you might implement full-blown, high-level security features in your application, but if somebody could simply access the physical database file directly, all the work you've spent on developing security might be in vain.
One of the fundamental security best practices is that you shouldn't rely on a single, big security barrier alone. Instead, it is often wiser to build security on different layers, and the previously mentioned database security is a great example. Unless you secure the database file itself, your application cannot be considered very secure.
Especially in complex IT environments, figuring correct file level security settings can be a tough job. Furthermore, actually applying and maintaining those settings can be time consuming. But with automation, the administrator can save hours and hours of work—and automation is something developers enjoy doing. Before checking what C# and the .NET Framework can do to help you secure your file systems, see what basic security options Windows gives.
File Access Control Lists
Especially with networked file servers and their file shares, you might have run into the Windows error message "Access denied." Although file shares also have their own security settings, most probably these errors result because somebody, likely the administrator, has restricted the user's access to certain files or folders.
In Windows, the NTFS file system supports file-level security settings; FAT-based file systems are out of luck. Simply put, these settings allow the creator of a given file (or the administrators) to specify who can access that file, and what can be done with it. For example, an administration might set file security so that Marketing can access certain files, but Sales cannot. This is called discretionary access control.
Figure 1 shows an example of security settings associated with a folder in Windows. With the Security tab, users with proper rights can precisely control in what way users and groups can access, modify, and delete files and folders. In Windows, these file-level security settings are one of the most low-level security settings that can be made. This means that you should build other security-related features on top of file-level security.
Figure 1: The Security tab in the Windows folder properties shows the access control entries associated with the object.
Technically speaking, file-level security settings are stored in so-called access control lists, or ACLs for short. Each ACL can contain zero or more (yes, and empty ACL is considered valid) access control entries, or ACEs. An ACE contains a security identifier (or SID) of a user or a group, entry type (access allowed or access denied), and a mask specifying which operations are either allowed or denied, depending on the entry type.
For example, a typical ACE might say that modifying a certain file is allowed for Jane, but denied from Peter. Although simple in concept, in the real world setting up access control lists isn't exactly as simple because you can make access control inheritable from parent directories. Similarly, the exact order of access control entries in the list is important. Luckily, the .NET Framework takes reasonably good care of the developer and modifying file security is much easier than it used to be when using the older Win32 API directly.
An Example of .NET's Support for File Access Control
When the .NET Framework 2.0 came along, it contained support for file access control lists built-in. In previous framework versions (namely 1.0 and 1.1), such support didn't exist, and you needed to use P/Invoke to call the operating system APIs directly.
Beginning with .NET 2.0, access control lists are represented using objects, most of which are defined in the System.Security.AccessControl namespace. In the case of files, the class named FileSecurity represents file ACLs. Getting a FileSecurity object instance is easy. You can call the static GetAccessControl method of the File class in the System.IO namespace, like this:
using System.IO; using System.Security.AccessControl; ... string filename = @"C:\MyFolder\My File.txt"; FileSecurity security = File.GetAccessControl(filename);
With the FileSecurity object, you are able to read and modify access control entries associated with the given file. For example, the GetAccessRules method returns a collection of access control entries (or actually, objects that represent them) that match the given parameters. For example, Windows allows access control lists to inherit from parent directories, and when you call the GetAccessRules method, you need to select whether you want to include such entries as well, for instance.
The FileSecurity object also supports multitude of other features, such as controlling audit policies (technically system ACLs), and adding, editing, and deleting (discretionary) access control entries, which are the focus of this article.