Export (0) Print
Expand All

How to: Run Partially Trusted Code in a Sandbox

Sandboxing is the practice of running an application in a restricted security environment, which limits the code access permissions granted to it. For example, controls that are downloaded to Internet Explorer run using the Internet permission set. Applications that reside on shares on your local area network run on your computer using the LocalIntranet permission set. (For more information about these permissions, see Named Permission Sets.)

You can use sandboxing to run partially trusted applications that you have downloaded to your computer. You can also use sandboxing to test applications you will be distributing that will run partially trusted in environments such as the intranet. For a complete description of code access security (CAS) and sandboxing, see Find Out What’s New with Code Access Security in the .NET Framework 2.0 on MSDN, the Microsoft Developer Network.

You can use the CreateDomain(String, Evidence, String, String, Boolean, AppDomainInitializer, String[]) method overload to specify the permission set for applications that run in a sandbox. This overload enables you to specify the permissions granted to an application, which provides the exact level of code access security you want. It does not utilize standard CAS policy (machine policy is not applied). For example, if the assembly that is called is signed with a strong name key and a custom code group exists for that strong name, the code group will not apply. Assemblies that are loaded by using this overload can either have the specified grant set only, or can have full trust. The assembly is granted full trust if it is in the global assembly cache or on the full trust list. However, targeting a full-trust assembly bypasses the use of a sandbox.

The overload has the following signature:

AppDomain.CreateDomain( string friendlyName,
                        Evidence securityInfo,
                        AppDomainSetup info,
                        PermissionSet grantSet,
                        params StrongName[] fullTrustAssemblies);

The parameters for the CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) method overload specify the name of the AppDomain, the evidence for the assembly, the AppDomainSetup object that identifies the application base for the sandbox, the permission set to use, and the strong name for trusted assemblies.

The application base specified in the info parameter should not be the application base for the hosting application. If it is, the hosted assembly will be able to use the Load method to load other assemblies into that folder, which may not have been designed to detect calls from partially trusted callers.

For the grantSet parameter, you can specify either a permission set you have explicitly created, or one of the named permission sets such as Internet or LocalIntranet. The complete example provided in this topic demonstrates how to use named permission sets instead of creating a custom permission set.

Unlike most AppDomain loads, the evidence for the assembly (which is provided by the securityInfo parameter) is not used to determine the grant set. Instead, it is independently specified by the grantSet parameter. However, the evidence can be used for other purposes such as determining isolated storage.

To run an application in a sandbox

  1. Create the permission set to be granted to the application.

    NoteNote:

    The application in this example requires Execution permission to run and UIPermission to write to the console. The following code creates a new permission set with those permissions. Alternatively, you can use an existing named permission set, such as LocalIntranet. For an example of how to use a named permission set, see the "Example" section later in this topic.

    PermissionSet pset = new PermissionSet(PermissionState.None);
    pset.AddPermission(new      SecurityPermission(SecurityPermissionFlag.Execution));
    pset.AddPermission(new UIPermission(PermissionState.Unrestricted));
    
  2. Initialize the folder that will be used as the sandbox. Do not use the folder that your hosting application is using. If you place the application in the hosting folder, the hosting assembly will have the ability to load any assembly in the folder.

    AppDomainSetup ads = new AppDomainSetup();
    // Identify the folder to use for the sandbox.
    ads.ApplicationBase = "C:\\Sandbox";
    // Copy the application you want to run to the sandbox. File.Copy("HelloWorld.exe","C:\\sandbox\\HelloWorld.exe",true);
    
  3. Use the CreateDomain(String, Evidence, String, String, Boolean, AppDomainInitializer, String[]) method overload to create the domain. In this case, the evidence and the strong name for the parent assembly is specified. See the "Example" section later in this topic for the code for the GetStrongName method.

    // Create the sandboxed application domain.
    AppDomain sandbox = AppDomain.CreateDomain(
    "Sandboxed Domain",
    AppDomain.CurrentDomain.Evidence,
    ads, pset, GetStrongName(Assembly.GetExecutingAssembly()));
    
  4. Run the application.

    sandbox.ExecuteAssemblyByName("HelloWorld");
    

The following example is a complete example that implements the procedure in the previous section. This example shows how you can run an application by using the same permissions it would be granted in an intranet environment. You will have to create your own test application to replace the HelloWorld.exe assembly in the example.

using System;
using System.Collections;
using System.Diagnostics;
using System.Security;
using System.Security.Permissions;
using System.Security.Policy;
using System.Reflection;
using System.IO;

namespace SimpleSandboxing
{
    class Program
    {
        static void Main(string[] args)
        {
            // Create the permission set to grant to other assemblies. 
            // In this case we are granting the permissions found in the LocalIntranet zone.
            PermissionSet pset = GetNamedPermissionSet("LocalIntranet");
            if (pset == null)
                return;
            // Optionally you can create your own permission set by explicitly adding permissions. 
            //     PermissionSet pset = new PermissionSet(PermissionState.None); 
            //     pset.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution)); 
            //     pset.AddPermission(new UIPermission(PermissionState.Unrestricted));
            AppDomainSetup ads = new AppDomainSetup();
            // Identify the folder to use for the sandbox.
            ads.ApplicationBase = "C:\\Sandbox";
            // Copy the application to be executed to the sandbox.
            File.Copy("HelloWorld.exe", "C:\\sandbox\\HelloWorld.exe", true);

            Evidence hostEvidence = new Evidence();
            // Commenting out the following two statements has no effect on the sample. 
            // The grant set is determined by the grantSet parameter, not the evidence  
            // for the assembly.  However, the evidence can be used for other reasons,  
            // for example, isolated storage.
            hostEvidence.AddHost(new Zone(SecurityZone.Intranet));
            hostEvidence.AddHost(new Url("C:\\Sandbox"));

            // Create the sandboxed domain.
            AppDomain sandbox = AppDomain.CreateDomain(
                "Sandboxed Domain",
                hostEvidence,
                ads,
                pset,
                GetStrongName(Assembly.GetExecutingAssembly()));
            sandbox.ExecuteAssemblyByName("HelloWorld");
        }

        /// <summary> 
        /// Get a strong name that matches the specified assembly. 
        /// </summary> 
        /// <exception cref="ArgumentNullException">
        /// if <paramref name="assembly"/> is null 
        /// </exception> 
        /// <exception cref="InvalidOperationException">
        /// if <paramref name="assembly"/> does not represent a strongly named assembly
        /// </exception> 
        /// <param name="assembly">Assembly to create a StrongName for</param>
        /// <returns>A StrongName for the given assembly</returns> 
        ///  
        public static StrongName GetStrongName(Assembly assembly)
        {
            if (assembly == null)
                throw new ArgumentNullException("assembly");

            AssemblyName assemblyName = assembly.GetName();
            Debug.Assert(assemblyName != null, "Could not get assembly name");

            // Get the public key blob. 
            byte[] publicKey = assemblyName.GetPublicKey();
            if (publicKey == null || publicKey.Length == 0)
                throw new InvalidOperationException("Assembly is not strongly named");

            StrongNamePublicKeyBlob keyBlob = new StrongNamePublicKeyBlob(publicKey);

            // Return the strong name. 
            return new StrongName(keyBlob, assemblyName.Name, assemblyName.Version);
        }
        private static PermissionSet GetNamedPermissionSet(string name)
        {
            IEnumerator policyEnumerator = SecurityManager.PolicyHierarchy();

            // Move through the policy levels to the machine policy level. 
            while (policyEnumerator.MoveNext())
            {
                PolicyLevel currentLevel = (PolicyLevel)policyEnumerator.Current;

                if (currentLevel.Label == "Machine")
                {
                    NamedPermissionSet copy = currentLevel.GetNamedPermissionSet(name);
                    return (PermissionSet)copy;
                }
            }
            return null;
        }

    }
}

Community Additions

ADD
Show:
© 2014 Microsoft