article

Security and Permissions in .NET

Email
Submitted on: 1/3/2015 3:39:00 PM
By: David N (from psc cd)  
Level: Intermediate
User Rating: By 4 Users
Compatibility: C#
Views: 1330
 
     The .NET Framework provides a rich set of permissions and security settings that (when used properly) ensures that your programs only do what their allowed to do. After searching for articles on security and permissions and finding virtually nothing here I decided to create this tutorial to explain the basic concepts. This simple tutorial explains how the Demand and Assert methods work. It also teach's you how to create a simple code group that grants a specific assembly more access to the system. Remember to vote!


 
				
After noticing virtually nothing on Planet-Source-Code.com about .NET security I decided to write this small tutorial.

The .NET Framework's security infrastructure is designed to prevent malicious code from gaining access to protected system resources such as the file system or registry. Its ability to do so lies a lot on the use of permissions. The base assemblies provided in the .NET Framework already make use of permissions for you. This makes sure that your application can only do what its given permission to do.

The .NET Framework assigns each assembly a set of permissions that it must adhere to when its loaded. You can look at how it determines what permissions go to what assemblies in the “.NET Configuration” (Look in “Administrative Tools” in the Control Panel). But for the most part assemblies are granted permissions based on where they came from (Local computer, Network share, Internet, etc.). You can create a special permission set for assemblies that require more access to the system. But doing so can expose system resources to malicious code if your not careful.

This simple tutorial will guide you through the process to gaining access to system resources (in a class library) while running with restricted permissions (in the client application).

SITUATION:
Assembly: MyLib.dll
  • Needs access to the file system.
  • Needs to prevent malicious code from gaining access to the file system.
    • This depends on the design and use of protected system resources within this library.
Source Code:
using System;
using System.IO;
using System.Security;
using System.Security.Permissions;
namespace MyLib {
public class MyFileIO {
public static int GetFileCount(string path) {
return Directory.GetFiles(path).Length;
}
}
}
Assembly: Client.exe
  • Needs to use the MyLib.dll assembly but doesn't need access to the file system directly.
  • Always running under the LocalIntranet permission set. (Which doesn't allow direct file system access.)
Source Code:
using System;
using System.Windows.Forms;
using MyLib;
namespace Client {
public class SimpleUI : Form {
public SimpleUI() {
this.Text = "Client Application";
Button btnTest = new Button();
btnTest.Text = "Test";
btnTest.Dock = DockStyle.Fill;
btnTest.Click += new EventHandler(this.OnTest);
this.Controls.Add(btnTest);
}
private void OnTest(object sender, EventArgs e) {
MessageBox.Show(MyFileIO.GetFileCount("C:\\").ToString());
}
private static void Main(string[] args) {
Application.Run(new SimpleUI());
}
}
}
Given the situation you need to give the MyLib.dll extra permissions because the LocalIntranet permission set doesn't allow file system access. You can use the .NET Configuration utility to do this fairly quickly and easily:

WARNING: These are “use at your own risk” instructions.
  1. Open the “.NET Configuration” (Look in “Administrative Tools” from the Control Panel)
  2. Expand to “Runtime Security Policy\Machine\Code Groups\All_Code\LocalIntranet_Zone”
  3. Click on “LocalIntranet_Zone” and then “Add a Child Code Group”
  4. Give the code group a name: “MyLib Security” (and description if you want.) Click Next.
  5. Change the membership condition to “Hash” (Cheap and simple) and then click “Browse...” and select the MyLib.dll assembly. Click Next.
  6. Select “FullTrust” (You should create a custom permission set to allow minimum access to system resources but this is easier for now) Click Finish.
NOTE: To execute your application in the LocalIntranet permission set you have to setup a network share (it can be on the local computer) and then copy the two assemblies there (MyLib.dll and Client.exe). Then click Start->Run and type something like "\\%COMPUTERNAME%\(share_name)\client.exe".
NOTE:: You can also use my "Secure Execution of .NET Scripts" program to execute this in a restricted permission set. This will require copying the MyLib.dll into the same folder as that program though.

Now that MyLib.dll has full access to the system it can freely access the file system. But there are problems when Client.exe tries to use MyLib.dll to access the file system. Why? Because in Directory.GetFiles() there is something like this:
// Demand PathDiscovery access to the given path.
new FileIOPermission(FileIOPermissionAccess.PathDiscovery, path).Demand();
NOTE: The Directory.GetFiles() method is only demanding "PathDiscovery" on the path.

The Demand method is implemented in System.Security.CodeAccessPermission which is also the base class for all permission classes in the .NET Framework. The Demand method here throws a SecurityException if any of the calling assemblies don't have access to the file system (In this case MyLib.dll has permission but Client.exe doesn't). So whats the point of giving permissions to MyLib.dll if it doesn't allow Client.exe access to the file system through it? Well thats where the Assert method comes into play. When the Demand method is used it walks the call stack up until it reachs the Main method or an Assert method. When an Assert method is encountered the security system in .NET stops looking higher in the call stack (The call stack grows down so the Main method is at the top of the call stack while the Directory.GetFiles() method is at or near the bottom). So in this case we can place an Assert method in the MyLib.dll so that the Demand in the Directory.GetFiles() method won't fail. Here's the new source code for MyLib.dll:
using System;
using System.IO;
using System.Security;
using System.Security.Permissions;
namespace MyLib {
public class MyFileIO {
public static int GetFileCount(string path) {
// begins a new "frame" with access to the file system.
new FileIOPermission(FileIOPermissionAccess.PathDiscovery, path).Assert();
int nFileCount = Directory.GetFiles(path).Length;
// required by .NET to end the "frame"
CodeAccessPermission.RevertAssert();
return nFileCount;
}
}
}
NOTE: We only need permission to "PathDiscovery" on this specific path so thats all we're asserting. Asserting more access than this could make us that much more vulnerable to attack.
NOTE: You have to update your code group in the .NET Configuration with the new hash.
  1. Click “MyLib Security” and click “Edit Code Group Properties”
  2. Goto the “Membership Condition” tab.
  3. Click “Import...” and select the newly compiled assembly.
  4. Click “OK”
The CodeAccessPermission.RevertAssert() is required as specified in the .NET documentation (Also note that you can only have one Assert per “frame”). By calling Assert your telling the security system to ignore Client.exe's permission to access the file system (This is where the CAUTION in the .NET documentation for this method comes into play: CAUTION: Because calling Assert removes the requirement that all code in the call chain must be granted permission to access the specified resource, it can open up security vulnerabilities if used incorrectly or inappropriately. Therefore, it should be used with great caution.”).

Now the Client.exe can use the MyLib.dll without any security exceptions being thrown.

As for the other methods in the System.Security.CodeAccessPermission class:
  • Deny() : Makes sure that code surrounded by Deny() and RevertDeny() doesn't have access to the permission.
  • PermitOnly() : Makes sure that code surround by PermitOnly() and ReveryPermitOnly() only has access to the permission.
The same methods have been implemented in the System.Security.PermissionSet class so that you can Assert, Deny, Demand, or PermitOnly an entire set of permissions.

Now that you have a basic understanding of how to give an assembly more access to system resources and allow assemblies with less permissions indirect access to those resources you can develope more functional and secure code. Just remember that the security of the system depends mainly on trusted assemblies and their use of system resources (Along with their use of Assert). Please vote!


Report Bad Submission
Use this form to tell us if this entry should be deleted (i.e contains no code, is a virus, etc.).
This submission should be removed because:

Your Vote

What do you think of this article (in the Intermediate category)?
(The article with your highest vote will win this month's coding contest!)
Excellent  Good  Average  Below Average  Poor (See voting log ...)
 

Other User Comments


 There are no comments on this submission.
 

Add Your Feedback
Your feedback will be posted below and an email sent to the author. Please remember that the author was kind enough to share this with you, so any criticisms must be stated politely, or they will be deleted. (For feedback not related to this particular article, please click here instead.)
 

To post feedback, first please login.