Login | Register   
RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX

By submitting your information, you agree that devx.com may send you DevX offers via email, phone and text message, as well as email offers about other products and services that DevX believes may be of interest to you. DevX will process your information in accordance with the Quinstreet Privacy Policy.


Never Write an Insecure ASP.NET Application Ever Again : Page 3

Learn to take advantage of the inner workings of ASP.NET's security model to help eliminate security vulnerabilities from your web applications.




Application Security Testing: An Integral Part of DevOps

ASP.NET Trust Level Implementation
To understand how ASP.NET implements trust levels, you have to explore sections of the root .NET configuration files. You'll normally find these in the C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG directory, although your actual name may vary a bit depending on the name of your Windows directory and the Framework version. Since this application deals only with ASP.NET features here, I won't bother reviewing the sections of machine.config, which contains settings for all .NET applications on the machine. Instead I'll just review the root web.config file, the basis for all ASP.NET applications.

Near the top of the root web.config file you'll find the <securityPolicy> and <trust> elements:

<system.Web> <securityPolicy> <trustLevel name="Full" policyFile="internal" /> <trustLevel name="High" policyFile="Web_hightrust.config" /> <trustLevel name="Medium" policyFile="Web_mediumtrust.config" /> <trustLevel name="Low" policyFile="Web_lowtrust.config" /> <trustLevel name="Minimal" policyFile="Web_minimaltrust.config" /> </securityPolicy> <trust level="Full" originUrl="" /> </system.Web>

The securityPolicy section defines the standard trust levels in ASP.NET: Full, High, Medium, Low, and Minimal. Each level grants your assemblies a set of specific permissions, going from unlimited permissions in Full trust to absurdly restrictive permissions in the Minimal trust level. The policyFile attribute specifies the file where the trust level is defined. The Full trust level uses "internal" as the policy file name; this level needs no additional configuration file because permission checking is effectively shut off.

The <trust> element sets the default trust level for all ASP.NET applications that don't override this setting. As you can see in the code above, it is set to Full when you install the .NET Framework, which becomes the default for all web applications on the machine. Fortunately you can—and should—override it in each application's web.config file.

In my opinion, a good starting level for most ASP.NET applications is the Medium trust level because it grants a reasonable set of permissions needed for most common web applications. The High trust level has far too many permissions, but at least it is better than Full because High doesn't allow running unmanaged code. Low and Minimal have far too few permissions to realistically run any non-trivial web application. So I'll use the Medium trust level as the starting point.

By the way, Microsoft's names for these trust levels might be a bit confusing. The higher the trust level, the more you trust the code is secure, and the more permissions it has. Low and Minimal ASP.NET applications are very untrustworthy, so they have too few permissions to realistically run a web application. High means that it is highly trusted code and it has almost all available .NET permissions. All this mumbo jumbo is yet another good reason to use a custom trust level tailored for the needs of a specific application.

If you examine the Medium trust level policy file, web_mediumtrust.config, you can see how ASP.NET defines a trust level. There are three major sections in this XML file: <SecurityClasses>, <NamedPermissionSets>, and <CodeGroup>. SecurityClasses includes a SecurityClass element for every permission, membership condition, and code group object used in this policy file. Each class is given an internal "friendly" name with the Name attribute and the Description attribute includes the strong name of the class. For example, this next code snippet shows the SecurityClass element for the permission that allows the code to connect to a SQL Server database (I've added line breaks to fit in the space; the entry is all on one line in the policy file):

<SecurityClass Name="SqlClientPermission" Description="System.Data.SqlClient.SqlClientPermission, System.Data, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>

The policy file includes three named permission sets: FullTrust, Nothing, and ASP.Net. The FullTrust permission set is again a special case. It doesn't have to list any permissions because the code has all permissions. Below you can see the FullTrust permission set definition:

<PermissionSet class="NamedPermissionSet" version="1" Unrestricted="true" Name="FullTrust" Description="Allows full access to all resources" />

The Unrestricted attribute is the important setting here. It tells the CLR to turn off permission checking for this assembly. The value of the Name attribute, FullTrust, is how the file assigns this set of permissions to a code group, which I'll get to soon.

The Nothing permission set, shown below, is of no real interest here. If an assembly has this trust level, it can do absolutely nothing, not even execute, so you're not likely to use it in most applications.

<PermissionSet class="NamedPermissionSet" version="1" Name="Nothing" Description="Denies all resources, including the right to execute" />

The ASP.Net permission set is what is interesting for partial trust applications. Through the <trust> element, it is the permission set assigned to the assembly, in this case at the Medium trust level. Here the policy file defines the specific permissions that will be assigned to an assembly at this trust level. This section begins with a PermissionSet element to define the name of the set:

<PermissionSet class="NamedPermissionSet" version="1" Name="ASP.Net">

The children of PermissionSet define the permissions that make up the set, contained within IPermission elements. Here is the IPermission element for the SqlClientPermission:

<IPermission class="SqlClientPermission" version="1" Unrestricted="true" />

This is the unrestricted form of a permission (Unrestricted="true"), meaning that code with a Medium trust level will have full access to SQL Server databases, without any limitations or restriction. That makes sense for database access, because once you allow code to connect to a database, it is up to the database to enforce any security restrictions.

Now let me illustrate a couple of restricted permissions:

<IPermission class="EnvironmentPermission" version="1" Read="TEMP;TMP;USERNAME;OS;COMPUTERNAME" /> <IPermission class="FileIOPermission" version="1" Read="$AppDir$" Write="$AppDir$" Append="$AppDir$" PathDiscovery="$AppDir$" />

You can tell that these are restricted forms of the permissions because they don't have the Unrestricted attribute set to true and they have one or more additional attributes that define the restriction. The EnvironmentPermission here allows read-only access to the TEMP, TMP, USERNAME, OS, and COMPUTERNAME environment variables only. It can't write to those variables, nor can it read or write any others that may exist on this machine. Note in particular that the Medium trust level grants no access to the PATH variable used by the sample application. I'll discuss that in more detail a little later in this article.

The FileIOPermission in Medium trust is also a restricted form of the permission, with four attributes defining the restriction. In this case the permission uses variables—with names starting and ending with a dollar sign—as placeholders for runtime values. $AppDir$ is the applications root directory. You can also use $AppDirUrl$ for the URI format of the root directory name (using the file:// protocol), $CodeGen$ for the temporary ASP.NET assembly directory, and $OriginHost$ for URIs that the application can connect to.

After the NamePermissionSet section in the medium trust policy file, you'll find the <CodeGroup> section. The policy file uses these elements to match assemblies with permission sets by assigning the assembly to one or more code groups. There is rich support for structuring a hierarchy of code groups, which gives you fine control over exactly which permissions sets an assembly gets. I'll gloss over most of the details here and let you explore them in the documentation. (See the sidebar, Help Writing Secure ASP.NET Applications, for a reference that goes into good detail about this hierarchy.)

Here is the CodeGroup element that assigns your web application's assemblies to the ASP.Net permission set:

<CodeGroup class="UnionCodeGroup" version="1" PermissionSetName="ASP.Net"> <IMembershipCondition class="UrlMembershipCondition" version="1" Url="$AppDirUrl$/*" /> </CodeGroup>

The CodeGroup element is of type UnionCodeGroup, which means that its permissions are added to those in the hierarchy. The PermissionSetName attribute links it to the ASP.Net permission set defined earlier in the file, and the IMembershipCondition element defines which assemblies belong to this code group. Here the membership condition is based on the location of the assembly, specifically all those in the application directory. This is how the assemblies you create as part of an ASP.NET application get the ASP.Net permission set that is part of the trust level defined by this config file.

Now that you understand how ASP.NET implements trust levels, let's look at how to change the trust level for an application.

Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.



We have made updates to our Privacy Policy to reflect the implementation of the General Data Protection Regulation.
Thanks for your registration, follow us on our social networks to keep up-to-date