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
- 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
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
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:
- Open your assembly project in Visual Studio.
- Open the AssemblyInfo.cs file.
- Add the following code in the "using" block at the top of the file (if it is not already there):
using System.Security; - Add the following line to the "assembly" section of the file:
[assembly: AllowPartiallyTrustedCallers] - 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:If there is no <trust> element in your Web.config file, you should add it within the <System.Web> element as follows:<trust level="Medium"/>
<system.web>
<trust level="Medium"/>
</system.web>