Trust Levels and Code Access Security


Code access security, commonly referred to as CAS, defines the execution permissions granted to a piece of code that runs in a partially trusted location. This concept is similar to user authorization, although it is the code and not a user account that is authorized. A partially trusted location does not fully trust the code that it contains and creates a restricted security context (that is, a sandbox) to isolate its code from the rest of the system.

Because the partially trusted location runs with restrictive permissions, it limits the attack surface of the system and is the most secure location from which to run code. The partially trusted location allows code to run in predefined security contexts without risk of compromising critical personal or corporate data. In WSS, each Web application’s bin directory is a partially trusted location in which code access security is enforced. Because of this fact, it is the preferred location to deploy Web Part applications. The least trusted location is the most secure place from which to run your code. Likewise, code that is trusted the least is the most secure because it is less likely to compromise the system.

The most common misunderstanding about CAS policy is that developers often think the least-trusted code is bad because we don’t trust it, and the code that we fully trust must be good. (We do trust it, don’t we?) In fact, the opposite is true. Because we do not grant trust for an unknown functionality, we know that we can trust the code not to execute malicious operations beyond its scope of defined trust. It is similar to having a dog on a leash. If the dog is loose, it may or may not behave. Yet the cat across the street may be too difficult to resist even if the dog does behave 99 percent of the time. If the dog is on a leash, however, you can trust that it will not run into the street. It is more trustworthy because there is an element of control that forces it to behave, regardless of the cat across the street.

Tip 

Least-trusted code is the most trustworthy code.

The Global Assembly Cache (GAC) is a fully trusted location for WSS, as is the _app_bin location. (The _app_bin location is a special location for WSS infrastructure components that should not be used for custom code.) Certain WSS components, such as feature receivers and event handlers, must be deployed to the GAC, so you should create separate assemblies for Web Parts to enable deployment in the bin directory. You should also think of your Web Part assemblies as security containers, in which the CAS policy is applied to the entire assembly. You may wish to limit the scope of a Web Part assembly by the security that it requires. If you have Web Part code that requires an abnormal amount of trust, it may be better to isolate that component in a security-isolated assembly rather than raise the trust of the rest of your code.

Tip 

The Web application’s bin directory is the preferred location for Web Part code because it has the most secure CAS policies. Web Part assembly DLLs that are installed in the GAC always run with full trust and cannot benefit from the ability to run code with partial trust in WSS.

CAS policies are aggregated into ASP.NET trust levels. Trust levels for the WSS Web application are defined in XML files and referenced in the Trust element of the web.config file. The trust level defines the amount of trust that is granted to predefined code groups running within the Web application context. This condition applies only to Web applications where code is deployed in the bin directory as a partially trusted code location. Code that runs as event handlers, admin console applications, or any other application outside of the Web application is not restricted and runs in full trust.

Default settings in the web.config for both WSS and Microsoft Office SharePoint Server (MOSS) run Web applications under a level of minimal trust. The custom trust levels that WSS defines and runs under are defined in the 12\CONFIG directory and include WSS_Minimal and WSS_Medium. These files are located at 12\config\wss_minimaltrust.config and 12\config\wss_mediumtrust.config. WSS also manages custom trust levels, defined as WSS_Custom, that are derived from solution package CAS policies. These CAS policy files are defined by the system by copying the most recent policy file and applying updates as needed. WSS maintains a change set per installed solution package. As a solution package is either deployed or retracted, it modifies the web.config of the Web site to which it is being installed.

Although most WSS developers tend to ignore CAS and the WSS trust levels by simply running in the full trust level or installing to the GAC, it is important to understand how WSS manages CAS because you might not be in control of the deployment environment. Although you can also bypass CAS entirely by running your assemblies in the GAC, this is not as secure as using controlled CAS policies. CAS policies affect not only your code, but all assemblies that might be available in the application. If you do not want to deal with CAS policies, it is better to install to the GAC than to set the trust level to full trust.

The benefit of strict CAS policies is that they allow the code to perform only trusted operations. For example, if you run in a restricted CAS policy (such as one derived from WSS_Minimal) that allows your code to call into the WSS object model, security demands within your code can prevent an untrusted assembly from using your code to call into the WSS object model. You can also have code that is allowed to make calls to certain trusted online XML data sources, such as security-scrubbed RSS feeds from NewsGator Online, while disallowing Web requests to unknown XML data sources by using the WebPermission’s ConnectAccess property. CAS policies allow IT to use third-party components without enabling the same level of trust that is granted to internally generated code or limiting the context in which code can execute. Web Part solutions that contain feature receivers should place the feature receiver in an external assembly that can be GAC installed, thereby maintaining a restrictive CAS policy for the Web assembly.

Tip 

Full trust escalates trust not only for your Web Part assembly DLL, but for all Web Part assembly DLLs.

The WSS_Minimal trust level denies code the right to execute certain calls or access certain resources such as Structured Query Language (SQL), Web requests, and even WSS object model access. These permissions are defined as CodeAccessSecurity classes and CodeAccessSecurityAttributes that are defined and demanded in the .NET Framework and Microsoft.SharePoint.Security.dll assembly. The WSS_Minimal trust level is the most secure, in which only Microsoft Web Parts and very basic functionality in custom Web Parts can execute. WSS_Medium is a common choice for most organizations because of its ease of development for Web Part developers, maintaining a balance of trust and ease of configuration. On the other hand, the default WSS_Minimal trust level is the most secure but requires more work to configure custom applications. As a SharePoint developer, you should always create components that can be installed to WSS_Minimal trust, with explicit trust policies documented and included in the solution package.

Tip 

When using WSS_Minimal trust and solution-managed trust levels, WSS manages the trust levels and creates custom trust levels based on the original configuration and installed solution packages. This is the recommended approach to maintaining WSS trust levels.

Within certain environments, you may wish to switch the trust level from WSS_Minimal to WSS_Medium or even full trust. This can be a viable choice for initial development environments, but for commercial or enterprise applications, you want to ensure that your solution has the correct permissions to execute (and no permissions not needed to execute). You may often want to develop in full trust and switch to WSS_Minimal to test your solution package deployments.

Tip 

As discussed in Chapter 9, “Solutions and Deployment,” solution packages are the supported and recommended way to set custom security levels. Other than switching the trust level during initial development, editing and managing security manually in configuration files is not maintainable on large scales and is not a recommended practice.

To examine the security ramifications of code access security, we will examine the SecurityWebPart code in Listing 10-1 that contains several security-sensitive calls, each of which demands a more sensitive security level. This Web Part runs in its entirety only in full or custom trust levels unless it is deployed to the GAC. For initial development (on the development box), we will deploy this assembly in full trust mode.

Listing 10-1: The example SecurityWebPart class demonstrates CAS security policies.

image from book
  CAS Example: Security Web Part using System; using Microsoft.SharePoint; using System.Security.Principal; namespace LitwareSecurity {   // An example Web Part demonstating CAS requirements   public class SecurityWebPart : System.Web.UI.WebControls.WebParts.WebPart {     protected override void RenderChildren(System.Web.UI.HtmlTextWriter writer) {       // Runs in WSS_Minimal       writer.Write(string.Format("Thread.CurrentPrincipal: {0} <br/>",         System.Threading.Thread.CurrentPrincipal.Identity.Name));       // Requires System.Security.Permissions.SecurityPermission       //  with SecurityPermissionFlag.ControlPrincipal       //  denied in the WSS_Minimal trust level..       writer.Write(string.Format("Current user: {0} <br/>",         WindowsIdentity.GetCurrent().Name) );       // Requires System.Security.Permissions.SecurityPermission       //  with SecurityPermissionFlag.ControlPrincipal       //  denied in the WSS_Minimal trust level.       using (WindowsImpersonationContext wic =           WindowsIdentity.Impersonate(IntPtr.Zero)) {         writer.Write(string.Format("Impersonated application pool user: {0} <br/>",           WindowsIdentity.GetCurrent().Name));       }       // Requires Microsoft.SharePoint.Security.SharePointPermission       // with ObjectModel = true       // denied in WSS_Minimal, allowed in WSS_Medium       writer.Write(string.Format("Current site: {0} <br/>",         SPContext.Current.Web.Title ));       // Requires Microsoft.SharePoint.Security.SharePointPermission       //  with Impersonate=true       //  denied in the WSS_Medium trust level,       //  allowed in Full or custom permissions       SPSecurity.RunWithElevatedPrivileges(        delegate() {           writer.Write(string.Format("RunWithElevatedPrivileges user: {0} <br/>",             WindowsIdentity.GetCurrent().Name));         }       );     }   } } 
image from book

However, before deploying to a staging, quality assurance, or production environment, we want to create a solution package with the appropriate CAS policies. The LitwareSecurity Web Part project is included in the code samples and includes the Web Part in Listing 10-1. To see CAS in action, first deploy the LitwareSecurity assembly manually in full trust mode. Next, add an instance of the SecurityWebPart to the page. Running this Web Part in anything but full trust breaks the Web Part.

To examine the effects of code access security, run this Web Part code in full trust and then reduce the trust levels to see what breaks. When reducing trust to WSS_Medium or lower, you will see an error message similar to the following:

 The "SecurityWebPart" Web Part appears to be causing a problem. Request for the permission of type 'Microsoft.SharePoint.Security.SharePointPermission, Microsoft.SharePoint.Security, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c' failed.

Although we cannot grant the CAS policy for the assembly within the assembly itself, we can define it within the solution package and set it during the installation. During initial development, we might choose to simply run the Web application in full trust for rapid prototyping, but we want to sign the assembly and set its trust level explicitly before deployment. Within the assembly, we also request the security permissions it requires, which causes an early failure at deployment time rather than a more obscure runtime error. Failed permission requests cause the assembly not to load and provide details in the form of a System.Security.Policy.PolicyException, with a message stating something similar to “Required permissions cannot be acquired.” By providing requests, we are letting the runtime know which permissions we require. The following example displays the permission request for the SharePoint permission.

 [assembly: SharePointPermission(SecurityAction.RequestMinimum, ObjectModel=true)]

By specifying the security action RequestMinimum, we are letting the runtime know that this is a minimal permission grant required for the assembly to run correctly. We could also use the RequestOptional security action that lets the runtime know that we would like a certain permission, but our assembly will still run even though it may be less functional without this permission. For example, we may want to enable certain functionality that requires permissions to use the SQL client, but this is not required for all Web Parts. Within the assembly, we could specify this by using the following permission request.

 [assembly: SqlClientPermission(SecurityAction.RequestOptional, Unrestricted=true)]

Likewise, if you want to refuse certain permissions from your assembly to take extra precautions to defend against luring attacks, you could use a RequestRefuse security action. The following permission refuses to allow the SQL client permission.

 [assembly: SqlClientPermission(SecurityAction.RequestRefuse)]

Security requests from the assembly do not grant the permissions. They only let the runtime know that the permissions are required for execution. For the LitwareSecurity assembly, prior to creating the policy in the solution package manifest, we will first document the intentions and needs of the assembly by performing the correct permission requests in the assembly information file. The following permission requests define the required minimal permissions needed for the LitwareSecurity assembly as well as some optional permissions required for our SecurityDebugWebPart Web Part.

 // Minimum permissions for the assembly to load: [assembly: AspNetHostingPermission(SecurityAction.RequestMinimum)] [assembly: SecurityPermission(SecurityAction.RequestMinimum,   Execution=true)] [assembly: SharePointPermission(SecurityAction.RequestMinimum,   ObjectModel=true, Impersonate=true, UnsafeSaveOnGet=true)] // Required by the optional Security Debug Web Part: [assembly: EnvironmentPermission(SecurityAction.RequestOptional)] [assembly: SecurityPermission(SecurityAction.RequestOptional,   ControlPrincipal = true)]

After defining the permission requests, the next step is to configure the CAS policy for the assembly. We will do this through the solution package, first by signing the assembly with the Litware public key and then by defining security policy in the solution package manifest.

Tip 

For a refresher on solution packages, see Chapter 9.

You can modify the solution manifest file to grant the required CAS levels for your Web Part assembly DLLs. When defining CAS policies, you can define the trust based on the assembly’s public key BLOB that is shared by all assemblies signed with your private key, or you can configure more granular trust based on the location of the assembly. Listing 10-2 shows a solution manifest that defines the permissions for Litware Security example code.

Listing 10-2: Security policy in the solution manifest

image from book
  Litware Security Solution Package Manifest <Solution SolutionId=""       xmlns="http://schemas.microsoft.com/sharepoint/">   <CodeAccessSecurity>     <PolicyItem>       <PermissionSet  version="1"             Description="Permission set for LitwareSecurity">         <IPermission  version="1" Level="Minimal" />         <IPermission  version="1"           Flags="Execution,ControlPrincipal,UnmanagedCode" />         <IPermission  version="1" ObjectModel="True" Impersonate="True"/>           <IPermission  version="1" Read="UserName" />       </PermissionSet>       <Assemblies>         <Assembly Name="LitwareSecurity" />       </Assemblies>     </PolicyItem>   </CodeAccessSecurity>   <Assemblies>     <Assembly DeploymentTarget="WebApplication" Location="LitwareSecurity.dll">       <SafeControls>         <SafeControl Assembly="LitwareSecurity, Version=1.0.0.0, Culture=neutral, PublicKeyToken=74bad7277fe0d19e"         Namespace="LitwareSecurity" TypeName="*" Safe="True"/>       </SafeControls>     </Assembly>   </Assemblies> </Solution> 
image from book

Note that within the solution manifest, each permission is defined in a NamedPermissionSet element. WSS creates a named permission set from this information. Within the permission set is a list of IPermission nodes, each of which defines a permission we are granting to members of this permission set. These IPermission nodes match the security requests we have already defined on the assembly. The three SharePoint permissions are also available in XML files in the 12\config folder. For a listing of the most common permissions used in WSS code, see the sidebar “Common Permission Definitions for WSS Applications” that follows.

image from book
Common Permission Definitions for WSS Applications

SharePointPermission   Defines permission to access the object model and permission to impersonate. ObjectModel, UnsafeSaveOnGet, and Impersonate are the optional properties that define the actual permission. UnsafeSaveOnGet specifies that the code has permission to update the database on a GET request. Note that this is also required for Web Service updates.

 <IPermission  version="1" ObjectModel="True" Impersonate="True"/>

EnvironmentPermission   Defines permission to access the environment, including the current Windows user.

 <IPermission  version="1" Read="UserName" />

SecurityPermission   Defines permissions specified by the SecurityPermissionFlag enumeration including AllFlags, Assertion, BindingRedirects, ControlAppDomain, ControlDomainPolicy, ControlEvidence, ControlPolicy, ControlPrincipal, ControlThread, Execution, Infrastructure, NoFlags, RemotingConfiguration, SerializationFormatter, SkipVerification, and UnmanagedCode. The WSS_Minimal trust level grants the SecurityPermission with the only Execute flag to code running in the bin directory.

 <IPermission  version="1" Flags="Execute" />

AspNetHostingPermission   Defines permission to access protected ASP.NET controls. This permission is granted in the WSS_Minimal trust level.

 <IPermission  version="1" Level="Minimal" />

WebPermission   Defines permission to access Web resources, including Web services. The ConnectAccess element defines which URLs can be accessed.

 <IPermission  version="1">   <ConnectAccess>     <URI uri="http?://.*" />   </ConnectAccess> </IPermission>

image from book

The permissions defined in the solution manifest are applied to the custom permission configuration managed by WSS. The following permission set is generated from the solution package.

 <PermissionSet  version="1" Description="Permission set for LitwareSecurity" Name="litwaresecurity.wsp--1">   <IPermission  version="1" Level="Minimal" />   <IPermission  version="1" Flags="Execution,ControlPrincipal, ControlAppDomain,ControlDomainPolicy,ControlEvidence" />   <IPermission  version="1" ObjectModel="True" Impersonate="True" />   <IPermission  version="1" Flags="ControlThread, UnmanagedCode" />   <IPermission  version="1" Read="UserName" /> </PermissionSet>

From the solution package, WSS modifies a copy of the WSS_Minimal permission set (or whichever permission set is referenced from web.config). For each solution package, a corresponding PermissionSet is created. The manifest GUID is applied to the solution package name, and a corresponding CodeGroup element is created. This code group is assigned to a permission set, and all code that matches its membership conditions is assigned this permission. In this case, the LitwareSecurity.dll assembly located in the bin directory is assigned to this permission set. The following code group is created from the solution package in the security configuration.

 <CodeGroup  version="1" PermissionSetName="litwaresecurity.wsp -1">   <IMembershipCondition version="1" Name="LitwareSecurity"  Url="$AppDirUrl$/bin/LitwareSecurity.dll" /> </CodeGroup>

The Listing 10-1 code example presented four methods that deal with identities and security. Each of these methods requires a specific grant of trust in order to execute. Because code access security is explicitly defined, it can be used to identify and audit security risks of an application. For example, we know that this assembly cannot be used to compromise a sensitive SQL database because we know it does not have the required permissions. Likewise, because this assembly does not have the System.Net.WebPermission granted, we know that it cannot be used to send data to remote Web endpoints regardless of any malicious code it could contain. Likewise, you could grant a restrictive System.Net.WebPermission that allows HTTP requests only to trusted endpoints, which enables the IT organization to limit its portal’s attack surface by restricting executable code to predefined sandboxes. In securitysensitive environments, the manifest file of the solution package is an auditable asset that should be examined before deployment.

Troubleshooting Code Access Security

Before deploying your solution package, you want to test it against the WSS_Minimal trust level. To do this, set the trust level to WSS_Minimal and run your installer script. Then, place Web Parts from the package on a Web Part page. If your code has not been granted the correct permissions, its security demands will fail. In the Web browser, you may get a security exception stating that the request for a security permission failed. At this point, you can search for the permission type in a tool, such as the Microsoft Visual Studio Object Browser, to find the arguments for the permission type. WSS permissions are defined in the 12\config directory; however, you may need to search MSDN or the appropriate class library for the correct properties and syntax. In general, permissions take the form of <IPermission Property="PropertyValue" />.

Next, examine the created permission set in the 12\config directory that corresponds with the WSS_Custom permission referenced in the web.config you are testing. Another common error is invalid configuration of the membership configuration. If you are not getting the expected results, check the IMembershipCondition element of your code group. For bindeployed assemblies, this is either the public key BLOB from the signed assembly manifest or the URL of the assembly location, such as $AppDirUrl$/bin/LitwareSecurity.dll in our example. This URL is created based on the assembly name in the solution manifest (without the file extension suffix), which is the simple file name and not the strong name of the assembly. The solution package creates either UrlMembershipCondition references based on the file name or StrongNameMembershipCondition references based on the public key BLOB from the assembly manifest.

Tip 

Microsoft Visual Studio 2005 Team Edition for Software Developers contains code analysis tools to help you write more secure code. Analyzing your code with Visual Studio exposes and helps you fix common CAS-related security vulnerabilities.




Inside Microsoft Windows Sharepoint Services Version 3
Inside Microsoft Windows Sharepoint Services Version 3
ISBN: 735623201
EAN: N/A
Year: 2007
Pages: 92

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net