Ограничить рефлексию в частных литеральных полях
Я пытаюсь построить песочницу, используя домен приложений, чтобы изолировать выполнение потенциально плохого кода.
Среди прочего я хотел бы ограничить рефлексию.
Я строю песочницу так:
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);
Он отлично работает с частными полями экземпляров и частными свойствами: любые попытки получить к ним доступ в песочнице отклоняются средой выполнения.
Но я заметил, что он не работает с литеральными полями (const в C#): всегда можно получить значение литерального поля, даже если private:
private const string PASSWORD = "secret";
private string password = "secret";
private string Password
{
get
{
return "secret";
}
}
пароль и пароль защищены правильно, но любой код может получить значение ПАРОЛЬ с базовым отражением:
string password = typeof(User).GetField("PASSWORD", BindingFlags.NonPublic | BindingFlags.Static).GetValue(currentUser) as string; // OK no problem take it, it's free!
Я хотел бы понять причины такого поведения: потому что литеральное значение всегда будет "легко" видимым в сборке, поэтому предотвращение отражения - проигрышная битва, или потому что окончательное значение на самом деле не "вызывается", поэтому существует нет проверки безопасности или...?
Этот пример не очень уместен, потому что пароль не будет общим, но представьте, что секретное значение - это солт-значение, используемое для криптографии или что-то подобное...
Спасибо за вашу помощь.
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);
}
}