views:

457

answers:

3

I have a C# application the performs some runtime compilation of source files containing calculations into dynamic assemblies. Obviously this presents a serious security issue.

From the following 'formula', the code below would be generated, and a dynamic assembly created:

Formula:

Int32 _index = value.LastIndexOf('.');
String _retVal = value.Substring(_index + 1);
return _retVal;

Code Generated:

using System;
namespace Dynamics
{
  public class Evaluator
  {
    public Object Evaluate(String value)
    {
      // Begin external code
      Int32 _index = value.LastIndexOf('.');
      String _retVal = value.Substring(_index + 1);
      return _retVal;
      // End external code
    }
  }
}

The dynamic assembly is then loaded and the Evaluate method executed via Reflection. This works Great.

The problem is that the potential for malicious code injection is huge, so I want to run the Evaluate method in a 'Sandboxed' thread (without any unmanaged API calls). For testing purposes I'm using the built in Anonymous Windows user, and have come up with the following code:

Thread tSandbox = new Thread(
    new ParameterizedThreadStart(this.DoSandboxedEvaluation));
WindowsIdentity tIdentity = WindowsIdentity.GetAnonymous();
WindowsPrincipal tPrincipal = new WindowsPrincipal(i);

This gives me the Anonymous users' Identity and Principal. How can this be applied to thread tSandbox so the code on that thread runs in the specified Security Context, without using Unmanaged API calls?

Thanks!

+3  A: 

AFAIK the only way to impersonate another user is via the unmanaged win32 apis (e.g., LogonUser())... You can call them through interop.

There's a code sample of this at http://msdn.microsoft.com/en-us/library/system.security.principal.windowsimpersonationcontext.aspx

Arnshea
Maybe I should have mentioned I'd like to avoid unmanaged calls. I realise I could do it with LogonUser and all the messing around that entails, but I was wondering if there was a 'better' way :pThanks anyway.
Dan
A: 

Search for the term "impersonation", you'll find some samples such as this one.

Lucero
+1  A: 

If you only need the anonymous account, you might be pretty close -- you just need to assign the principle to the thread (you do this from code running within the thread that you want to change by setting System.Threading.CurrentPrinciple)

However, if you need to authenticate a Windows user and assign that identity to the thread, I think that you are going to have to make an unmanaged call to LogonUser(). I don't see a way around that.

Here's some code that works with the anonymous user (it assumes an ASP.Net Web ApplicationProject, where you have a tag on the form named "identityLabel", and you have assigned onInit="IdentityLabelInit") (note the code runs differently depending upon whether you are running it under IIS or Cassini -- under IIS, the initial identity is the anonymous user. Under Cassini, the initial identity was me.


        protected void IdentityLabelInit(object sender, EventArgs e)
        {
            System.Threading.Thread testThread = new Thread(ReportIdentity);
            testThread.Start();
            testThread.Join();
        }

        private void ReportIdentity()
        {
            identityLabel.InnerText = "Initialized: " + System.Threading.Thread.CurrentPrincipal.Identity.Name;
            System.Security.Principal.IPrincipal currentPrincipal = System.Threading.Thread.CurrentPrincipal;
            SetAnonymousIdentity();
            System.Security.Principal.IPrincipal newPrincipal = System.Threading.Thread.CurrentPrincipal;
            if (newPrincipal.Equals(currentPrincipal))
                identityLabel.InnerText += ("no change");
            else
                identityLabel.InnerText += " | new name: " + System.Threading.Thread.CurrentPrincipal.Identity.Name;
        }

        private void SetAnonymousIdentity()
        {
            WindowsIdentity tIdentity = WindowsIdentity.GetAnonymous();
            WindowsPrincipal tPrincipal = new WindowsPrincipal(tIdentity);
            System.Threading.Thread.CurrentPrincipal = tPrincipal;
        }

JMarsch