The Simple Sandboxing API


A while back I gave some sample code to show how to setup a sandboxed AppDomain.  This technique has worked since v1.0, and will continue to work with Whidbey.  However, Whidbey also introduces a simple sandboxing API which eliminates the need for this boilerplate code, and makes setting up a sandboxed AppDomain trivial for your application.


This API is exposed as a new overload of AppDomain.CreateDomain:


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


The first three parameters should be familiar, since they’re also used in other CreateDomain overloads. Where the simple sandboxing API gets interesting is with the last two parameters. These provide the permission set to grant to all assemblies in the domain, and a set of assemblies that should be treated as fully trusted.


These two parameters define the way that the sandboxed domain will trust assemblies.  A sandboxed domain created with the simple sandboxing API has assemblies loaded with at most two grant sets.  Either the assembly is fully trusted, or it is granted the permission set passed in via the grantSet parameter.


An assembly will be fully trusted if it meets one of two conditions, if neither of these conditions are met it receives grantSet:



  1. The assembly is in the GAC

  2. It is strongly named and its strong name should match one of the names passed in through the fullTrustAssemblies parameter.

We can easily construct a StrongName object for an assembly in the same way we created StrongNameMembershipCondition objects:


    /// <summary>
    /// Create a StrongName that matches a specific 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 that matches the given assembly</returns>
    public static StrongName CreateStrongName(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);

        // and create the StrongName
        return new StrongName(keyBlob, assemblyName.Name, assemblyName.Version);
    }


 


With that bit of code in place, it’s now pretty trivial to create an AppDomain that grants, say only Execution permission to any assembly but the currently running one.



// create the permission set to grant other assemblies
PermissionSet pset = new PermissionSet(PermissionState.None);
pset.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));

// create the sandboxed domain
AppDomain sandbox = AppDomain.CreateDomain(
    “Sandboxed Domain”,
    AppDomain.CurrentDomain.Evidence,
    new AppDomainSetup(),
    pset,
    CreateStrongName(Assembly.GetExecutingAssembly()));

// transfer control to the new appdomain
// …

Clearly this API makes setting up a sandboxed domain much easier than the old method, which required you to setup an entire policy level, deal with various code groups, etc.


Next time we’ll take a deeper look at the created domain, and discover what may be some surprising properties that it has.

Comments (10)

  1. Yesterday we took a look at Whidbey’s new Simple Sandboxing API.&amp;nbsp; At first glance this API does…

  2. mihailik says:

    Hmm, it seems this API introduces huge secuirty flaw.

    Every assembly loaded in such AppDomain will have at least ‘grantSet’ permissions. They have no option to restrict execution of some code group.

    Right scenario to use this API is keeping ‘grantSet’ restrictive. But dumb developer can do it wrong. It is possible malicious code come into and get many privileges in this AppDomain.

  3. This API makes it easier for an application to sandbox code. Previously, the app developer had to deal with setting up an entire policy tree, which is much more difficult to get correct. This way, he just says what he wants the sandboxed code to get.

    A developer misusing the API is not a security hole.

    -Shawn

  4. Keith Brown says:

    This is great, Shawn. As for mihailik’s concern, I assume the creator’s assembly must either be fully trusted or have something like ControlPolicy+ControlEvidence, pretty much the equivalent of full trust anyway?

  5. Absolutely — to call this API you need to have ControlAppDomain.

    -Shawn

  6. While we’re on the topic of AppDomains …

    One feature of AppDomains that many people don’t know about…

  7. There’s a ton of new and enhanced security features coming with the v2.0 release of the CLR.&amp;nbsp; However,…

  8. There’s a ton of new and enhanced security features coming with the v2.0 release of the CLR.&amp;nbsp; However,…

  9. Michael says:

    An assembly will be fully trusted if it meets one of two conditions, if neither of these conditions are met it receives grantSet:

    – The assembly is in the GAC

    – It is strongly named and its strong name should match one of the names passed in through the fullTrustAssemblies parameter.

    Arrrgghh…

    Is there any way to disable that "The Assembly is in the GAC" ? I’m looking for a way to sandbox a third party assembly which installs in the GAC by default, is there a (simple) way to do this ?

  10. Hi Michael,

    There is no way to sandbox a GACed assembly.  When an administrator installs an assembly into the GAC they are effectively making a decision to include that assembly as part of the platform that all code on the machine can build upon.  Because of that, the CLR will always treat everything from the GAC as FullTrust (and in fact give it other special treatment, like not verifying its strong name every time its loaded).

    Since any code, even code running from an untrusted web site, can access everything in the GAC, having something that needs to be sandboxed living in the GAC doesn’t make much sense … your host is not going to be around to sandbox it in all cases, so it’s inherently unsafe to have it in the GAC if you don’t trust it.

    -Shawn