Monday, October 10, 2011

Executing Code in Partial Trust Environments


When building your first .NET web service, you may be in for a rude awakening when you discover the concept of "partial trust." Your previously bullet-proof code will suddenly fail in a flurry of exceptions thrown by seemingly innocuous commands such as reading files or accessing the Registry. This article provides a brief overview of Code Access Security and describes how to modify and test your code to work in a partial trust environment.

Code Access Security

Code Access Security (CAS) in the .NET Framework limits the access that code has to protected resources and operations. CAS is separate from and in addition to the security provided by the host operating system.
When a user runs a .NET application, the .NET Common Language Runtime (CLR) assigns the application to one of the following zones:
  • My Computer — application code runs directly on the user's computer
  • Local Intranet — application code runs from a file share on the user's intranet
  • Internet — application code runs on the Internet
  • Trusted Sites — application code runs on a web site defined as "Trusted" by Internet Explorer
  • Untrusted Sites — application code runs on a web site defined as "Restricted" by Internet Explorer
For each zone, a system administrator can set specific access permissions, represented by permission objects. The more common permissions include:
  • FileIOPermission — ability to work with files
  • OleDbPermission — access databases with OLEDB
  • PrintingPermission — ability to print
  • SecurityPermission — ability to execute, assert permissions, call into unmanaged code, skip verification and other rights
  • SocketPermission — ability to make/accept TCP/IP connections
  • SQLClientPermission — access SQL databases
  • UIPermission — provide a user interface
  • WebPermission — connect to/from the Web
These permissions determine which resources the application can access and can represent a security level of full trust, medium trust, low trust, or no trust.

What is Partial Trust?

Developers usually work in a full-trust environment–their own PC. Typically any code the developer compiles is allowed to run on the local computer without security restrictions or errors.
Partial trust describes any zone that is not a full trust zone. The most common scenarios where code runs in partial trust are:
  • .NET web services on a shared host
  • Code downloaded from the Internet
  • Code that resides on a network share (intranet)

Permission Denied

The following resources are typically available in full trust but are denied in a partial trust zone:
  • File I/O, including reading, writing, creating, deleting or printing files
  • System components, such as registry values, environment variables and assembly information
  • Server components, including directory services, event logs, performance counters, and message queues
  • Reflection
It's not always easy to determine which code can run in partial trust. Each class in the .NET Framework has a security attribute that defines the level of trust needed to access it. The table below shows the typical permissions allowed for each trust level:
Allowed Permissions Full Trust Medium Trust Low Trust
DnsPermission yes yes no
EnvironmentPermission yes no no
EventLogPermission no no no
FileIOPermission yes no no
OleDbPermission no no no
RegistryPermission yes no no
SecurityPermission no no no
SocketPermission yes no no
SqlClientPermission yes yes no
WebPermission yes no no

Security Exceptions

If you attempt to execute full-trust code in a partial trust environment, CAS will throw the following SecurityException:



System.Security.SecurityException: That assembly does not allow partially trusted callers.
at System.Security.CodeAccessSecurityEngine.ThrowSecurityException( Assembly asm, PermissionSet granted, PermissionSet refused, RuntimeMethodHandle rmh, SecurityAction action, Object demand, IPermission permThatFailed)
at …
The action that failed was:
LinkDemand

Operate in Partial Trust

Applications operating in partial trust are not allowed to call a .NET assembly unless the assembly is specifically marked to operate in partial trust. Here's why:
Assemblies must be signed with a strong name in order to be shared by multiple applications. A strong name enables your assembly to be placed in the Global Assembly Cache and makes it difficult for hackers to spoof your code. By default, strong-named assemblies automatically perform an implicit LinkDemand for full trust. If a caller operating in partial trust attempts to call such an assembly, CAS throws a SecurityException.
To disable the automatic LinkDemand and prevent the exception from being thrown, add the AllowPartiallyTrustedCallersAttribute (APTCA) to the assembly. This attribute enables your assembly to be called from partially trusted code. Note the APTCA is applicable only on the assembly level, so you cannot provide partial trust for an individual method or class; either everything in the assembly is safe to use by partially trusted code, or none of it is.
To set the APTCA on your assembly:
  1. Open your assembly project in Visual Studio.
  2. Open the AssemblyInfo.cs file.
  3. Add the following code in the "using" block at the top of the file (if it is not already there):
    using System.Security;
  4. Add the following line to the "assembly" section of the file:
    [assembly: AllowPartiallyTrustedCallers]
  5. Rebuild the assembly.

Check for Partial Trust

Because many resources are not available in partial trust, you will likely want to check the trust level at runtime and respond accordingly. Following is sample code to check for full trust. Call the CheckTrust() method once in the static constructor of the class in which you placed this code, for example, then call the IsFullTrust property as needed:
using System.Security;
using System.Security.Permissions;
static private void CheckTrust()
{
try
{
FileIOPermission permission =
new FileIOPermission( PermissionState.Unrestricted );
s_FullTrust = SecurityManager.IsGranted( permission );
}
catch (Exception)
{
// ignore
}
}

static private bool s_FullTrust;
static public bool IsFullTrust
{
get
{
return s_FullTrust;
}
}

Test in Partial Trust

If you test your web service on your local PC (localhost), it will typically operate in full trust, which of course is not an accurate representation of a partial trust web host. So to force the web service to run under partial trust, modify the <trust> element in the application's Web.config file as follows:
<trust level="Medium"/>
If there is no <trust> element in your Web.config file, you should add it within the <System.Web> element as follows:
<system.web>
<
trust level="Medium"/>
</
system.web>