Sandboxing in .NET 4.0

Yesterday I talked about the changes in security policy for managed applications, namely that managed applications will run with full trust - the same as native applications - when you execute them directly.

That change doesn’t mean that managed code can no longer be sandboxed however - far from it.  Hosts such as ASP.NET and ClickOnce continue to use the CLR to sandbox untrusted code.  Additionally, any application can continue to create AppDomains to sandbox code in.

As part of our overhaul of security policy in v4, we made some interesting changes to how that sandboxing should be accomplished as well.  In previous releases, the CLR provided a variety of ways to sandbox code – but many of them were problematic to use correctly.  In the v4 framework, we made it a goal to simplify and standardize how sandboxing should be done in managed code.

One of the key observations we made about sandboxing is that there really isn’t a good reason for the CLR to be involved in the decision as to what grant set should be given to partial trust code.   If your application says “I want to run this code with ReflectionPermission/RestrictedMemberAccess and SecurityPermission/Execution”, that’s exactly the set of permissions that the code should run with.   After all, your application knows much better than the CLR what operations the sandboxed code can be safely allowed to undertake.

The problem is, sandboxing by providing an AppDomain policy level doesn’t provide total control to the application doing the sandboxing.  For instance, imagine you wanted to provide the sandbox grant set of RestrictedMemberAccess + Execution permission.  You might setup a policy level that grants AllCode this grant set and assign it to the AppDomain.   However, if the code you place in that AppDomain has evidence that says it came from the Internet, the CLR will instead produce a grant set that doesn’t include RestrictedMemberAccess for the sandbox.  Rather than allowing safe partial trust reflection as you wanted, your sandbox just became execute-only.

This really doesn’t make sense – what right does the CLR have to tell your application what should and should not be allowed in its sandboxes?  In the v1.x release of the runtime, developers had to go to great lengths in order to ensure they got the grant set they wanted.  (Eric Lippert’s CAS policy acrobatics to get VSTO working correctly is the stuff of legends around the security team – fabulous adventures in coding indeed!).

As many a frustrated application developer found out, intersecting with the application supplied grant set was only the tip of the iceburg when it came to the difficulties of coding with CAS policy.  You would also run into a slew of other problems – such as each version of the CLR having an entirely independent security policy to deal with.

In v2.0, we introduced the simple sandboxing API as a way for applications to say “This is the grant set I want my application to have.  Please don’t mess with it.”.  This went a long way toward making writing an application which sandboxes code an easier task.

Beginning with v4.0, the CLR is getting out of the policy business completely.  By default, the CLR is not going to supply a CAS policy level that interferes with the wishes of the application that is trying to do sandboxing.

Effectively, we’ve simplified the multiple ways that you could have sandboxed code in v3.5 into one easy option – all sandboxes in v4 must be setup with the simple sandboxing API.

This means that the days of wrangling with complicated policy trees with arbitrary decision nodes in them are thankfully a thing of the past.  All that’s needed from here on out is a simple statement: “here is my sandboxed grant set, and here are the assemblies I wish to trust.”

Next time, I’ll look at the implications of this on code that interacts with policy, looking at what you used to write, and what it would be replaced with in v4.0 of the CLR.