.net 4.0安全模型。另一个“类型违反的继承安全规则......”例外

时间:2014-02-04 10:43:13

标签: c# .net appdomain code-access-security typeloadexception

我认为我坚持使用.net 4.0新的安全模型。通常,我只想将第三方程序集加载到沙箱中。听起来很简单吧?尽管如此...

我的解决方案中有2个项目:CrossAppDomain.exe和UntrustedCode.dll。 在CrossAppdomain中,我为所有的marshallables创建了以下基类:

public abstract class Marshallable : MarshalByRefObject, IDisposable
{
    [SecurityCritical]
    public override object InitializeLifetimeService()
    {
        return null;
    }

    public void Dispose()
    {
        if (!RemotingServices.IsTransparentProxy(this))
        {
            RemotingServices.Disconnect(this);
        }
    }
}

为我将使用的对象创建基类

public abstract class BaseClass : Marshallable
{
}

在UntrustedCode.dll中,我创建了开源类

public class UntrustedClass : BaseClass
{
}

要创建UntrustedClass的实例,请使用以下工厂:

   public sealed class Factory
{
    public BaseClass Create(string assName, string typeName)
    {
        var domain = CreateAppDomain();

        ObjectHandle handle;
        try
        {
            // This throws SecurityException with informational message "RequestFailed"
            handle = domain.CreateInstance(typeof(AppDomainWorker).Assembly.FullName, typeof(AppDomainWorker).FullName);
        }
        catch (SecurityException)
        {
            // While this works fine...
            handle = Activator.CreateInstanceFrom(domain,
                                                      typeof(AppDomainWorker).Assembly.ManifestModule.FullyQualifiedName,
                                                      typeof(AppDomainWorker).FullName);
        }
        var worker = (AppDomainWorker)handle.Unwrap();
        worker.LoadAssemblies();

        var obj = worker.Create(assName, typeName);
        worker.Dispose();
        return obj;
    }

    private AppDomain CreateAppDomain()
    {
        var name = Guid.NewGuid().ToString();
        var permissions = new PermissionSet(PermissionState.None);
        permissions.AddPermission(new SecurityPermission(PermissionState.Unrestricted));
        permissions.AddPermission(new ReflectionPermission(PermissionState.Unrestricted));
        permissions.AddPermission(new FileIOPermission(PermissionState.Unrestricted));
        var appSetup = new AppDomainSetup
            {
                ApplicationName = name,
                ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase,
                ShadowCopyDirectories = Path.GetFullPath(@"..\..\..\UntrustedCode\bin"),
                ShadowCopyFiles = "true"
            };
        // Since Marshallable.InitializeLifetimeServices is overriden and marked with [SecurityCritical] 
        // we should add this assembly in full trusted list.
        // Otherwise. TypeLoadException is thrown with message "Inheritance security rules violated while overriding member: 
        // 'CrossAppDomains.Marshallable.InitializeLifetimeService()'. Security accessibility of the overriding method must 
        // match the security accessibility of the method being overriden.
        var sn = typeof (AppDomainWorker).Assembly.Evidence.GetHostEvidence<StrongName>();
        var domain = AppDomain.CreateDomain(name, null, appSetup, permissions, sn);
        return domain;
    }

    private sealed class AppDomainWorker : Marshallable
    {
        public BaseClass Create(string assName, string typeName)
        {
            var assembly = AppDomain.CurrentDomain.GetAssemblies()
                                    .Single(a => assName.StartsWith(a.GetName().Name));

            // Here TypeLoadException is thrown: Inheritance security rules violated by type: 'UntrustedCode.UntrustedClass'. 
            // Derived types must either match the security accessibility of the base type or be less accessible.
            var obj = (BaseClass)Activator.CreateInstanceFrom(assembly.Location, typeName).Unwrap();
            Debug.Assert(!RemotingServices.IsTransparentProxy(obj));
            return obj;
        }

        public void LoadAssemblies()
        {
            var assemblyName = AssemblyName.GetAssemblyName(Path.GetFullPath(@"..\..\..\UntrustedCode\bin\Debug\UntrustedCode.dll"));
            Assembly.Load(assemblyName);
        }
    }
}

这里出现问题:

  1. 在Factory.Create()中,只有当我使用Activator.CreateInstance时才成功创建AppDomainWorker类。虽然更直接的AppDomain.CreateInstanceAndUnwrap失败了。这看起来很不稳定,我的意思是这是错误或安全漏洞。但没关系,解决方法正常工作
  2. 在AppDomainWorker.Create()中,我收到TypeLoadException :违反了类型的继承安全规则:'UntrustedCode.UntrustedClass'。派生类型必须与基本类型的安全可访问性匹配,或者不太容易访问。我不知道如何解决它。这是我的问题

    P.S。我知道[assembly:SecurityRules(SecurityRuleSet.Level1)],但我想知道如何使用.net 4.0安全模型工作

  3. 编辑:添加[assembly:AllowPartialTrustCallers]后,我遇到了一大堆新问题:我需要用[SecuritySafeCritical]明确标记使用LogManager.GetCurrentClassLogger()创建nlog loggger的所有代码然后全部使用带有记录器的初始化字段的代码。这是不可接受的。那么也许还有其他办法吗?

1 个答案:

答案 0 :(得分:1)

我认为,我只需将UntrustedClass使用的类和使用安全关键代码的代码移动到单独的程序集中。

即。将BaseClass,Marshallable,Factory移动到一些Api.dll中。然后使用[APTCA]标记装配并使用[SecuritySafe]装饰必要的方法。然后任何现有的代码应该没有问题,因为[APTCA]仅适用于Api.dll。

这种方法适用于示例项目,但我无法确定它是否适合我当前的项目。我一实施,就告诉你。