【问题标题】:Restrict reflection on private literal fields限制对私有文字字段的反射
【发布时间】:2013-09-27 20:03:25
【问题描述】:

我正在尝试使用应用程序域构建一个沙盒,以隔离潜在错误代码的执行。

我想限制反射

我正在以这种方式构建沙盒:

AppDomainSetup sandboxSetup = new AppDomainSetup
{
    ApplicationBase = "."
};
PermissionSet permissions = new PermissionSet(PermissionState.None);
permissions.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
AppDomain sandbox = AppDomain.CreateDomain("sandbox", null, sandboxSetup, permissions);

私有实例字段和私有属性可以正常工作:在沙箱中访问它们的任何尝试都会被运行时拒绝。

但我注意到它不适用于 literal fields(C# 中的 const):总是可以获得 literal 的值字段,即使是私有的:

private const string PASSWORD = "secret";
private string password = "secret";
private string Password
{
    get
    {
        return "secret";
    }
}

passwordPassword 得到了正确保护,但是任何代码都可以通过基本反射获得 PASSWORD 的值:

string password = typeof(User).GetField("PASSWORD", BindingFlags.NonPublic | BindingFlags.Static).GetValue(currentUser) as string;  // OK no problem take it, it's free!

我想了解这种行为背后的基本原理:是因为字面值在程序集中总是“容易”可见,因此防止反射是一场失败的战斗,还是因为最终值并未真正“调用”所以没有安检还是……?

这个例子并不真正相关,因为密码不会被共享,但假设秘密值是用于加密的盐值或类似的东西......

感谢您的帮助。

【问题讨论】:

    标签: c# .net reflection appdomain reflectionpermission


    【解决方案1】:

    当您为常量获得FieldInfo 时,您将获得MdFieldInfo 类型。 如果我们反编译代码,我们会发现它没有对该类型进行安全检查。

    这是MdFieldInfo 类型的反编译代码:

    [DebuggerHidden]
    [DebuggerStepThrough]
    [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
    public override object GetValue(object obj)
    {
      return this.GetValue(false);
    }
    [SecuritySafeCritical]
    private object GetValue(bool raw)
    {
      object obj = MdConstant.GetValue(this.GetRuntimeModule().MetadataImport, this.m_tkField, this.FieldType.GetTypeHandleInternal(), raw);
      if (obj == DBNull.Value)
        throw new NotSupportedException(Environment.GetResourceString("Arg_EnumLitValueNotFound"));
      else
        return obj;
    }
    

    当您为非常量值获得 FieldInfo 时,您将获得 RtFieldInfo 类型,它会进行安全检查。

    这是RtFieldInfo 类型的反编译代码:

    public override object GetValue(object obj)
    {
      StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
      return this.InternalGetValue(obj, ref stackMark);
    }
    
    [SecuritySafeCritical]
    [DebuggerStepThrough]
    [DebuggerHidden]
    internal object InternalGetValue(object obj, ref StackCrawlMark stackMark)
    {
      INVOCATION_FLAGS invocationFlags = this.InvocationFlags;
      RuntimeType runtimeType1 = this.DeclaringType as RuntimeType;
      if ((invocationFlags & INVOCATION_FLAGS.INVOCATION_FLAGS_NO_INVOKE) != INVOCATION_FLAGS.INVOCATION_FLAGS_UNKNOWN)
      {
        if (runtimeType1 != (RuntimeType) null && this.DeclaringType.ContainsGenericParameters)
          throw new InvalidOperationException(Environment.GetResourceString("Arg_UnboundGenField"));
        if (runtimeType1 == (RuntimeType) null && this.Module.Assembly.ReflectionOnly || runtimeType1 is ReflectionOnlyType)
          throw new InvalidOperationException(Environment.GetResourceString("Arg_ReflectionOnlyField"));
        else
          throw new FieldAccessException();
      }
      else
      {
        this.CheckConsistency(obj);
        if ((invocationFlags & INVOCATION_FLAGS.INVOCATION_FLAGS_NON_W8P_FX_API) != INVOCATION_FLAGS.INVOCATION_FLAGS_UNKNOWN)
        {
          RuntimeAssembly executingAssembly = RuntimeAssembly.GetExecutingAssembly(ref stackMark);
          if ((Assembly) executingAssembly != (Assembly) null && !executingAssembly.IsSafeForReflection())
            throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_APIInvalidForCurrentContext", new object[1]
            {
              (object) this.FullName
            }));
        }
        RuntimeType runtimeType2 = (RuntimeType) this.FieldType;
        if ((invocationFlags & INVOCATION_FLAGS.INVOCATION_FLAGS_NEED_SECURITY) != INVOCATION_FLAGS.INVOCATION_FLAGS_UNKNOWN)
          RtFieldInfo.PerformVisibilityCheckOnField(this.m_fieldHandle, obj, this.m_declaringType, this.m_fieldAttributes, (uint) (this.m_invocationFlags & ~INVOCATION_FLAGS.INVOCATION_FLAGS_IS_CTOR));
        return this.UnsafeGetValue(obj);
      }
    }
    

    【讨论】:

    • 感谢 Vyacheslav 提供的反编译代码明确显示未对文字字段实施安全检查。主要问题仍然存在:为什么?无论如何+1 :)
    猜你喜欢
    • 2011-02-02
    • 1970-01-01
    • 2013-02-25
    • 2019-01-23
    • 1970-01-01
    • 2010-09-10
    • 2011-05-29
    • 2015-07-08
    • 2021-12-07
    相关资源
    最近更新 更多