Overview of Windows® NT Security Subsystem
Before you enter the world of Windows NT security programming, you need a quick overview of Windows NT security. This article provides a basic introduction to the Windows NT security architecture.
Windows NT consists of components called subsystems. The security subsystem controls how objects (e.g., files) are accessed. The implementation of the security subsystem is rather complex. First, more than 75 security-related Windows NT API functions are available to developers. Furthermore, the structures that are used for security checks are overly complicated. It definitely takes an investment of time to get a clear picture of how the security subsystem works.
Surprisingly, in spite of all the complexities, the general idea of Windows NT Security is simple.
- An owner of a resource (such as a file) must be able to control access to the resource.
- System administrators must be able to audit security-related events. Access to this audit data must be limited to authorized administrators.
- Each user must identify himself or herself before being allowed access to the system. The system uses a protected mechanism (e.g., passwords) to authenticate the user's identity. The system must provide the capability of associating a user's identification with all auditable actions taken by this user.
According to the C2 specification, these are the most important attributes of a secure operating system. One of the key points is that the owner of an object should have the means to restrict certain users (or all users) from performing certain operations (or all operations) on the object. Basically, this stipulation means that an owner of an object must have the ability to associate his or her object with a discretionary list that describes who can do what with the object. If the object is a file, for instance, the owner could say that only user A may write to the file, and everyone else may only read from it.
You may be wondering how such simple ideas led to such a complex implementation. In fact, the C2 specification document has other requirements, and each one must be met in order for Windows NT to fit the C2 security specification. (The full text of the C2 specification is given in my recently published book, Windows NT Security.) The complexity of C2 specification creates a kind of monster that scares many developers away, and much of this complexity seems unnecessary. I am convinced that Windows NT security can be made more developer friendly through the use of carefully designed C++ classes that would allow the developer to protect objects with a couple lines of code. One of the tasks of this book is to gradually present the security class library, which makes Windows NT security easier to implement. Another task is to describe native security the right way, without the use of recursion. At this point. however, we are more interested in understanding security.
To quickly characterize Windows NT security: every user is assigned a unique security identifier. From the moment a user logs on with a valid logon name and password, every process the user runs is associated with that user's security identifier. Every securable object in the system is associated with two lists. One list describes who is allowed access and what kind of access is allowed. The other list specifies users whose interaction with the object should be recorded (audited) in the system security log. When a user attempts to access an object, the system checks whether the user is listed in the first list with the necessary access rights. The system also checks the second list to determine whether an event should be recorded in the security log. This action is independent of the outcome of the access check.
Figure 1 describes the interaction between users and objects in Windows NT. Each object is protected individually by Windows NT security, and any user may try to access any object. Access is given depending on who the user is and what security information is associated with an individual object.
Figure 1 also shows the interaction of security elements at the very top level. Each attempt to access the object is successful or unsuccessful based on two kinds of information: one associated with a process running on a user's behalf and the other associated with the object. Figure 2 represents an individual interaction between a user and an object.
Each securable object is associated with a data structure called a security descriptor. The security descriptor contains all the information the system needs to control access to the object, including a discretionary access control list. Each user, on the other hand, is associated with a bundle of security information in the form of an access token. The access token uniquely identifies the user and supplies other security-related information. Windows NT controls access to an object by checking the security information stored in a user's access token and comparing it to the security information stored in the object's security descriptor.
An access token is assigned to a user when he or she successfully logs on to the system. Any process the user starts is associated with a copy of the original access token. Thus, the system knows who stands behind every process in the system. This is also true for remote users.
It is impossible to run a process without an associated access token. When an access token is attached to a process, it is usually said that the process has the security context of the user whose access token is associated with the process. Suppose that John Smith logs on to a Windows NT workstation, supplying a correct user name and password, then starts Notepad. The Notepad process is running in the security context of John Smith. Any files that the user tries to open with Notepad are subject to a security check for access by John Smith.
If Mr. Smith starts several processes on the system, they all will have identical access tokens, and all will act within the same security context. From the point of view of security, it really does not matter which application Mr. Smith runs. Access will be allowed or denied based not on the process (application) but on the access token associated with that process. The purpose of the security subsystem is to restrict users (not just abstract processes) from access to objects. It is important who Mr. Smith is, not what tools he uses. A key concept here is that not all code is trusted. Applications are executed within the security context of a user account. Attacks on the system, either preplanned or accidental (a bug, for instance) may influence the system only within the limits accorded to the user account.
Figure 3 shows a detailed representation of a security descriptor. The first element of a security descriptor is the security identifier (SID) of the owner of an object. The SID is simply a unique identifier (a number) that distinguishes this particular user from all other users. The SID is a universally unique ID: no two different users may have the same SID.
The next component in the security descriptor is a Discretionary Access Control List (DACL). The DACL describes who is allowed access and who is denied access to the object. The DACL is actually just a collection of security identifiers, each associated with additional information specifying the kind of access allowed or denied. This list is called discretionary because when it is constructed (usually by the owner) any individual SID may be listed. For example, you can deny access to John Smith once you know his SID.
Windows NT allows an owner to modify an object's discretionary access control list. Thus, an owner gains unlimited access to the object by first inserting an appropriate entry into the object's DACL. An owner can easily destroy the object, but the operation itself must be allowed through modification of the DACL.
The last component in the security descriptor is a System Access Control List (SACL). The SACL regulates audits of access to this particular object. The SACL is very similar to the DACL in that it represents a collection of SIDs along with other information. In this case, the other information specifies what should be audited. For example, you may specify that an event must be recorded when Mr. Smith tries to read from a top secret file. You can then review the security log and estimate any damage Mr. Smith may have perpetrated.
In summary, security information contained in security descriptors consists of three important parts:
- Owner's SID - a security identifier that shows who owns the object. The owner is allowed to modify the discretionary access control list, and, through this privilege, can have unlimited access to the object.
- Discretionary Access Control List (DACL) - A list that contains individual SIDs, along with specifications defining the access permissions for the user associated with each SID.
- System Access Control List (SACL) - a list that contains individual SIDs as well as specifications defining types of access attempts that will generate audit messages if the user associated with each SID attempts to gain access to the object.
Figure 4 shows the components of an access token. The first component is the SID of the user standing behind the process. If you log on to the system and examine your own access token, you will see that this component is your own security identifier.
The next component in the access token is a list of group SIDs. The group model provides a way to see a given individual user as a collection of identities, one identity being the user's unique identity and the others being the identities of groups of which the user is a member. To illustrate this visually, imagine a user carrying a collection of passes (or keys) when accessing a restricted area. One pass lets the user access one room in the area, and another pass allows access to a more secure room. For now, the important thing to remember is that each user is treated as a collection of security identifiers. Note in Figure 4 that an owner's SID is followed by a list of group SIDs. By accessing this list in the access token, you can learn all the identities of this particular user.
The next component of the access token is a list of privileges. Privileges are rules governing activities that are not associated with a particular object. Some users (called backup operators) need to backup all files in the system regardless of the permissions on individual files. This is an example of a job that requires interaction with every file object on the system. Although it is theoretically possible to store permissions for backup operators in security descriptors associated with files, storing backup permissions with individual files is obviously not a very efficient solution, because the security descriptor for every file would have to contain the required permissions. Windows NT includes a backup operator privilege, which gives a user the right to backup files independent of individual file permissions.
Other jobs also cannot be secured by the means of security descriptors; for example, setting system time or collecting profile information about the entire system. As in the case of a backup operator, a privilege must not only be independent of security descriptors, but must sometimes actually bypass regular security checks as applied by security descriptors. Privileges provide a means to secure certain kinds of operations that cannot be secured directly through the use of security descriptors. A privilege is a well-defined special activity that can be given by an administrator to any user or group.
There are a number of privileges, and each privilege has a name. For example, the privilege to backup files is called SE_BACKUP_NAME. The list of privileges within the access token is an accumulated list, which means it contains every privilege assigned to this particular user and each group to which he or she belongs.
The last two components of an access token are the default owner SID and the default discretionary access control list. These components are required for default Windows NT security. For example, when you use Win32 API functions and supply NULLs instead of real security information, the default owner and default DACL may be extracted from your access token and attached to objects that you create. The default owner and default DACL ensure that Windows NT security works even when you are not aware of it.
To summarize, the following security information is contained in an access token:
- User's SID - A security identifier of the user who started the process. The user's SID defines the security context for the process.
- List of group SIDs - Security identifiers of every group to which the user belongs.
- List of privileges - Special privileges accorded the user, such as the ability to backup files or set the system clock.
- Default owner SID - A security identifier that may be inserted by default into security descriptors of objects the user creates (e.g., when NULLs are supplied instead of real security structures in Win32 API functions).
- Default discretionary access control list - A DACL that may be inserted by default in security descriptors of objects the user creates (e.g., when NULLs are supplied instead of real security structures in Win32 API functions that create objects in Windows NT).
Security information is stored with objects in the form of a security descriptor and with processes in the form of an access token. Access to objects is allowed or denied based on the information in both these structures. If a user's SID, or the SID of any group to which the user belongs, has the requested rights in the discretionary access control list of the security descriptor, access is given (unless it is explicitly denied to the user or any groups to which the user belongs). When a user requests a secured operation that is not protected by a security descriptor, or when the requested operation may require Windows NT to bypass the security descriptor, the security subsystem checks privileges contained in the user's access token. Privileges provide extensions to the security associated with objects (in security descriptors) and are rarely needed for most users.
About the Author
Nik Okuntseff is a Microsoft Certified Solution Developer with Infowave Wireless Messaging, Inc., a Canadian wireless communication company. He formerly worked for Software Metrics, Inc., a Canadian consulting firm, and the Russian Academy of Sciences after graduating from the Moscow Institute of Phiysics and Technology. He can be reached at NikOkuntseff@WRConsulting.com. His book, Windows NT Security, is available from R&D Books: www.rdbooks.com.