Using ASP.NET Components in a Medium Trust Environment

This KB entry includes instructions on how to configure a custom security level to allow the components to work in a medium trust environment.

Date Entered: 03/30/2012    Last Updated: 04/18/2012

This MSDN article: "How To: Use Medium Trust in ASP.NET 2.0" discusses working in, and configuring medium
trust permissions. Here are some key points about medium trust:

  • By default, ASP.NET 2.0 Web applications and Web services run with full trust and applications can
    perform privileged operations and access resources subject only to operating system security and
    Windows access control lists (ACLs). You can use code access security (CAS) to restrict access to certain
    resources by using the trust element of the web.config. You can set full, high, medium, low, and minimal trust.
  • Medium restricts you from using OldDbPermission, EventLogPermission, ReflectionPermission,
    RegistryPermission, calling unmanaged code, and using Enterprise Services. Also WebPermission (you can
    only communicate with address(es) defined in the trust element) and FileIOPermission (You can only access
    files in your applications virtual directory hierarchy) are restricted.
  • To turn on medium trust, set the trust level to medium in your app-level or machine-level web.config
    (<trust level="Medium" />). Consider the originUrl attribute for the trust element, which allows you to limit what
    URLs the web application(s)
    can access.
  • You can customize medium trust restrictions (e.g., modify FileIOPermission to allow access to a specific
    directory outside the applications virtual directory hierarchy) by creating a custom policy file and custom
    policy level. There is an example of this provided in the article.

For the most part any shared host (3rd party web host etc.) is going to have the medium trust level configured
by default.

In general, all /n software .NET components will need the following permissions, all of which are granted by default
in Medium trust except SocketPermission:

  • FileIOPermission - all components, for licensing and file access.
  • ReflectionPermission - all components, for licensing
  • SocketPermission - all components that use socket communication
  • DnsPermission - anytime a hostname is used instead of a dotted IP address

On a shared host you will likely not have access to the main configuration file. What this means is
that you will need to setup a web.config that is local to your application and configure a custom trust level with
the required permissions.

To configure a file for a custom trust level and to use that custom trust level you will need to add a new security
policy and trust level to the web.config

To do that modify the top of the system.web section so it looks as follows:

<configuration>
	<system.web>
		<securityPolicy>
      			<trustLevel name="Custom" policyFile="web_customtrust.config" />
		</securityPolicy>
		<trust level="Custom" originUrl="" /> 
...

This defines a new trust level named custom using the file web_customtrust.config (in the same directory) and then
sets the current trust level to "Custom".

The next step is to create the custom trust config file and configure it to your needs.

<configuration>
    <mscorlib>
        <security>
            <policy>
                <PolicyLevel version="1">
                    <SecurityClasses>
                        <SecurityClass Name="AllMembershipCondition" Description="System.Security.Policy.AllMembershipCondition, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
                        <SecurityClass Name="AspNetHostingPermission" Description="System.Web.AspNetHostingPermission, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
                        <SecurityClass Name="DnsPermission" Description="System.Net.DnsPermission, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
                        <SecurityClass Name="EnvironmentPermission" Description="System.Security.Permissions.EnvironmentPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
                        <SecurityClass Name="FileIOPermission" Description="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
                        <SecurityClass Name="FirstMatchCodeGroup" Description="System.Security.Policy.FirstMatchCodeGroup, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
                        <SecurityClass Name="IsolatedStorageFilePermission" Description="System.Security.Permissions.IsolatedStorageFilePermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
                        <SecurityClass Name="NamedPermissionSet" Description="System.Security.NamedPermissionSet"/>
                        <SecurityClass Name="PrintingPermission" Description="System.Drawing.Printing.PrintingPermission, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
                        <SecurityClass Name="SecurityPermission" Description="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
                        <SecurityClass Name="SmtpPermission" Description="System.Net.Mail.SmtpPermission, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
                        <SecurityClass Name="SqlClientPermission" Description="System.Data.SqlClient.SqlClientPermission, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
                        <SecurityClass Name="StrongNameMembershipCondition" Description="System.Security.Policy.StrongNameMembershipCondition, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
                        <SecurityClass Name="UIPermission" Description="System.Security.Permissions.UIPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
                        <SecurityClass Name="UnionCodeGroup" Description="System.Security.Policy.UnionCodeGroup, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
                        <SecurityClass Name="UrlMembershipCondition" Description="System.Security.Policy.UrlMembershipCondition, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
                        <SecurityClass Name="WebPermission" Description="System.Net.WebPermission, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
                        <SecurityClass Name="ZoneMembershipCondition" Description="System.Security.Policy.ZoneMembershipCondition, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
                        <SecurityClass Name="ReflectionPermission" Description="System.Security.Permissions.ReflectionPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
                        <SecurityClass Name="SocketPermission" Description="System.Net.SocketPermission, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
                     </SecurityClasses>
			
                    <NamedPermissionSets>
                        <PermissionSet class="NamedPermissionSet" version="1" Unrestricted="true" Name="FullTrust" Description="Allows full access to all resources"/>
                        <PermissionSet class="NamedPermissionSet" version="1" Name="Nothing" Description="Denies all resources, including the right to execute"/>
                        <PermissionSet class="NamedPermissionSet" version="1" Name="ASP.Net">
                            <IPermission class="AspNetHostingPermission" version="1" Level="Medium"/>
                            <IPermission class="DnsPermission" version="1" Unrestricted="true"/>
                            <IPermission class="EnvironmentPermission" version="1" Read="TEMP;TMP;USERNAME;OS;COMPUTERNAME"/>
                            <IPermission class="FileIOPermission" version="1" Read="$AppDir$" Write="$AppDir$" Append="$AppDir$" PathDiscovery="$AppDir$"/>
                            <IPermission class="IsolatedStorageFilePermission" version="1" Allowed="AssemblyIsolationByUser" UserQuota="9223372036854775807"/>
                            <IPermission class="PrintingPermission" version="1" Level="DefaultPrinting"/>
                            <IPermission class="SecurityPermission" version="1" Flags="Assertion, Execution, ControlThread,
                              ControlPrincipal, RemotingConfiguration, SkipVerification, UnmanagedCode, SerializationFormatter"/>
                            <IPermission class="SmtpPermission" version="1" Access="Connect"/>
                            <IPermission class="SqlClientPermission" version="1" Unrestricted="true"/>
                            <IPermission class="WebPermission" version="1">
                                <ConnectAccess>
                                    <URI uri="$OriginHost$"/>
                                </ConnectAccess>
                            </IPermission>
                            <IPermission class="SocketPermission" version="1" Unrestricted="true" />
                            <IPermission class="ReflectionPermission" version="1" Flags="RestrictedMemberAccess"/>
                         </PermissionSet>
                    </NamedPermissionSets>
                    <CodeGroup class="FirstMatchCodeGroup" version="1" PermissionSetName="Nothing">
                        <IMembershipCondition class="AllMembershipCondition" version="1"/>
                        <CodeGroup class="UnionCodeGroup" version="1" PermissionSetName="ASP.Net">
                            <IMembershipCondition class="UrlMembershipCondition" version="1" Url="$AppDirUrl$/*"/>
                        </CodeGroup>
                        <CodeGroup class="UnionCodeGroup" version="1" PermissionSetName="ASP.Net">
                            <IMembershipCondition class="UrlMembershipCondition" version="1" Url="$CodeGen$/*"/>
                        </CodeGroup>
                        <CodeGroup class="UnionCodeGroup" version="1" PermissionSetName="Nothing">
                        	<IMembershipCondition class="ZoneMembershipCondition" version="1" Zone="MyComputer"/>
                            <CodeGroup class="UnionCodeGroup" version="1" PermissionSetName="FullTrust" Name="Microsoft_Strong_Name" Description="This code group grants code signed with the Microsoft strong name full trust. ">
                                <IMembershipCondition class="StrongNameMembershipCondition" version="1" PublicKeyBlob="002400000480000094000000060200000024000052534131000400000100010007D1FA57C4AED9F0A32E84AA0FAEFD0DE9E8FD6AE
                                C8F87FB03766C834C99921EB23BE79AD9D5DCC1DD9AD236132102900B723CF980957FC4E177108FC607774F29E8320E92EA05ECE4E821C0A5EFE8F1645C4C0C93C1AB99285D622CAA652C1DFAD63D745D6F2DE5F17E5EAF0FC4963D261C8A124365
                                18206DC093344D5AD293"/>
                            </CodeGroup>
                            <CodeGroup class="UnionCodeGroup" version="1" PermissionSetName="FullTrust" Name="Ecma_Strong_Name" Description="This code group grants code signed with the ECMA strong name full trust. ">
                                <IMembershipCondition class="StrongNameMembershipCondition" version="1" PublicKeyBlob="00000000000000000400000000000000"/>
                            </CodeGroup>
                        </CodeGroup>
                    </CodeGroup>
                </PolicyLevel>
            </policy>
        </security>
    </mscorlib>
</configuration>

Note: If you copy and paste the above example verify that values are not incorrectly line wrapped or you may encounter unexpected compilation errors.

There are only 3 differences between this custom security policy and default medium trust level:

  • The last line in the SecurityClasses section (<SecurityClass Name="SocketPermission" Description="System.Net.SocketPermission...)
    which grants the permission to access the sockets that the medium trust level did not allow
  • The IPermission class="SocketPermission" under the NamedPermissionSets which allows us to configure the
    SocketPermission. Inside this we set "Unrestricted" to true which allows
    the permission state unrestricted access
  • The modifications to the Security Permission IPermission (adding the SkipVerification, UnmanagedCode,
    and SerializationFormatter flags).
    • SkipVerification and UnmanagedCode are needed if the managed SSL implementation is not used in the component (default).
    • SerializationFormatter is needed if the Microsoft .NET licensing scheme is used (default).
    Please find more information on these settings below.


SSL, SSH, and other Cryptographic Configuration Options

By default, the components that use SSL, SSH, AES, or other protocols and algorithms requiring cryptographic operations
will use the Microsoft Crypto API. Since the CyrptoAPI is unmanaged, this requires access to unmanaged code. In the above
example setting SkipVerification and UnmanagedCode allows this. The components can also be configured to use an internal
implementation that is 100% managed instead. To do this set:

component.Config("UseManagedSecurityAPI=true");

This setting instructs the component to use the internal managed implementation instead of Microsoft's CryptoAPI.
When this setting is enabled the SkipVerification and UnmanagedCode flags are not required in the
SecurityPermission IPermission.

When using the managed implementation make sure that there is no system dll (i.e.: nsoftware.InPayPal.System.dll)
in the bin directory of your application or else .NET will default to running as unmanaged after trying to verify it. If
this happens the SkipVerification and UnmanagedCode flags will also still be required as the code will be running unmanaged.

Note: Visual Studio may automatically try to import the system dll if you added a reference from the Solution Explorer.
To prevent this, manually place the dll directly in the Bin folder of your website instead of adding a reference from Visual Studio.

Licensing

By default the component uses the Microsoft .NET licensing scheme. The article KB 01020301
provides more detail. To use this licensing scheme set the SerializationFormatter as mentioned above.

<IPermission class="SecurityPermission" version="1" Flags="Assertion, Execution, ControlThread, ControlPrincipal,
RemotingConfiguration, SkipVerification, UnmanagedCode, SerializationFormatter"/>

To compile the license, make sure your component is listed in the licenses.licx file in your solution, right click on it, and select
Build Runtime Licenses. A file called App_Licenses.dll will be built in your /bin directory and will need to be deployed along
with your application.

An alternative is to provide a runtime license to the constructor of the component. For more information on this
approach contact support@nsoftware.com


We appreciate your feedback.  If you have any questions, comments, or suggestions about this entry please contact our support team at kb@nsoftware.com.