.NET Security Workshop
Home About Workshops Articles Writing Talks Books Contact

2. Security Architecture

.NET security is layered over Win32 security: it does not replace Win32. This means that if .NET uses a secured Win32 object Win32 access checks will be performed and if those fail then the .NET code will not be able to access the object. .NET security is applied after Win32 security has been applied.

Win32 security is based on access tokens and access control lists. When you log on to Windows a security session will be started for your account and each process will be given a security token. This token associates the process with a logon session, and there can be more than one logon session running on a machine at a single time. The most obvious process that is started for you when you logon is Explorer. This process provides the shell, the start menu, the task bar and the desktop as well as Windows Explorer. Explorer will be given the token that refers to your logon session. Typically, when you launch a process you will do this through Explorer: either the start menu, the run dialog, a desktop shortcut or Windows Explorer. When Explorer starts another process the system will make a copy of Explorer's token and hand it to the new process. In this way, the security token, and the information it contains, will be availableto all processes started by you.

Win32 secured objects (for example a file, or a registry value) are created with a security descriptor. The security descriptor contains two access control lists (ACL), one to specify the accounts that can access the object (the Discretionary ACL) and another that controls auditing (the System ACL). An ACL contains a list of accounts. The DACL contains a list of the accounts that are denied access to the object and the accounts that are granted access. The SACL also contains a list, but this list determines if an audit message is generated if the specified user is denied access to the object, and if the specified user is granted access to the object.

If the process tries to access a secured object then Win32 checks the DACL of the object to see if the user represented by the process's access token has access to the object, the system also checks the SACL to determine the audit policy for this user and object. This means that the process access token is very important, and if the process is hijacked by rogue code this bad code will have access to the secured objects that the process had access to, and those accesses will be audited to the user identified by the token.

Clearly, it is very important that you prevent rogue code from running. Attaching an access token to a process and performing access checks against a DACL is a great convenience, but it has the inherent danger that a Trojan could get access to secure objects. Further, using a SACL to provide auditing according to the user identified by the access token is also a great convenience, but again, this means that a Trojan can perform some restricted operation and it will be audited to you! 

.NET prevents code hijacking through code access security (CAS).

.NET provides an equivalent of access checks through principal based security. There are two types. .NET principal based security allows you to perform access checks against .NET principals and groups. However, you have to be careful how you set up .NET role based security because you have the choice over whether to use your Windows principal or a custom principal. The other type is Enterprise Services role based security, in other words COM+ role based security. COM+ always uses the Windows principal, so there are no issues about initialising.

.NET Version 3.0
In version 1.1 and version 1.0 .NET ignores access control lists entirely. However, .NET version 3.0/2.0 now has classes that allow you to manipulate Win32 access control lists. These classes will be covered on page nine.

2.1 NTFS Security and .NET Classes

We will use file access to show how .NET is layered over Win32 security. The System.IO.FileStream class is used to access a file. This class's methods will perform code access checks, but in this part of the tutorial we will ignore what CAS is doing. The following code (fileinfo.cs) opens a file and prints some information on the command line:

using System;
using System.IO;

class App
   static void Main(string[] args)
      using (FileStream fs = new FileStream(args[0], FileMode.Open))
         Console.WriteLine("File is {0} bytes", fs.Length);

The using statement ensures that the file will be closed regardless of how the guarded block is left. That is, if the access to the Length property succeeds or throws an exception then the file will be closed. Compile this code. Now create a file for these tests, the contents are unimportant. For example, create a file called data.txt. Run the example passing the name of the test file, here are the results I get:

C:\TestFolder\fileinfo data.txt
File is 4 bytes

Now use Windows Explorer to change the ACL on the data file. To do this you must make sure that your machine does not use simple file sharing. If you use XP Professional you should always run without this option in spite of Microsoft's recommendation. To do this, access Folder Options on the Tools menu and select the View tab. If the Use simple file sharing option is checked then uncheck it.

With simple file sharing disabled you can access the file's properties through Windows Explorer and select the Security tab. Select your user account in the top box and then deny Read and Read & Execute permissions:

When you click OK or Apply you'll be asked to confirm this action, click Yes to indicate that you want to continue with this action.

Note that in this case the object (data.txt) inherits default values from its parent, which for a file will be the folder that contains the file. You can indicate that the object should not inherit the ACL from its parent using the Advanced button, but we do not need to do this. The reason is that if you deny access this always overrides a DACL entry that grants access, so in the screenshot I am both denied and granted Read access to the file, but the combination will mean that I will be denied Read access.

Now run the fileinfo process again and you'll find that an UnauthorizedAccessException exception is thrown:

Unhandled Exception: System.UnauthorizedAccessException: Access to the path "c:\temp\data.txt" is denied.
   at System.IO.__Error.WinIOError(Int32 errorCode, String str)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, Boolean useAsync, String msgPath, Boolean bFromProxy)
   at System.IO.FileStream..ctor(String path, FileMode mode)
   at App.Main(String[] args)

This shows that if Win32 security denies access the .NET classes will not be able to give you access. Use Windows Explorer to uncheck the deny access boxes and restore access to this file to your account.

I hope that you enjoy this tutorial and value the knowledge that you will gain from it. I am always pleased to hear from people who use this tutorial (contact me). If you find this tutorial useful then please also email your comments to mvpga@microsoft.com.


If you see an error on this page, please contact me and I will fix the problem.

Page Three

This page is (c) 2007 Richard Grimes, all rights reserved