Соображения о безопасности для отражения

Отражение дает возможность получать информацию о типах и членах, а также обращаться к членам (то есть вызывать методы и конструкторы для получения и задания значений свойств, добавления и удаления обработчиков событий и т. д.). Использование отражения для получения информации о типах и членах не ограничено. В любом коде отражение можно использовать для выполнения следующих задач:

  • перечисления типов и членов и просмотра их метаданных;
  • перечисления и просмотра сборок и модулей.

На использование отражения для доступа к членам, напротив, накладываются ограничения. Начиная с .NET Framework 4 только полностью доверенный код может использовать отражение для доступа к членам, критически важным с точки зрения безопасности. Кроме того, только полностью доверенный код может использовать отражение для доступа к закрытым членам, которые недоступны компилированному коду непосредственно. Наконец, код, который использует отражение для доступа к критическим с точки зрения безопасности членам, должен иметь все разрешения, требуемые этим членом, то есть ситуация такая же, как с компилированным кодом.

В зависимости от необходимых разрешений код может использовать отражение для осуществления следующих видов доступа:

  • доступ к открытым членам, которые не являются критическими с точки зрения безопасности;

  • доступ к закрытым членам, которые доступны скомпилированному коду, только если не являются критическими с точки зрения безопасности. Примерами подобных закрытых членов являются:

    • защищенные члены базовых классов вызывающего кода (в отражении это называется доступом на уровне семейства);

    • члены internal (члены Friend в Visual Basic) в сборке вызывающего кода (в отражении это называется доступом на уровне сборки);

    • закрытые члены других экземпляров класса, содержащего вызывающий код.

Например, для кода, выполняемого в изолированном домене приложения, доступ ограничен видами, перечисленными в этом списке, пока домену приложения не будут предоставлены дополнительные разрешения.

Начиная с .NET Framework 2.0 с пакетом обновления 1 (SP1) при попытке доступа к членам, которые обычно недоступны, запрашивается набор прав для целевого объекта и разрешения ReflectionPermission с флагом ReflectionPermissionFlag.MemberAccess. Код, выполняемый с полным доверием (например, код в приложении, которое запускается из командной строки), может всегда удовлетворять этим разрешениям. (К нему применяются ограничения доступа к членам, критическим с точки зрения безопасности, описанные ниже в данном разделе.)

При необходимости изолированный домен приложения может предоставить разрешение ReflectionPermission с флагом ReflectionPermissionFlag.MemberAccess, как описано в разделе Доступ к обычно недоступным членам далее в этой статье.

Доступ к членам, критическим с точки зрения безопасности

Член является критическим с точки зрения безопасности, если у него есть атрибут SecurityCriticalAttribute, если он относится к типу с атрибутом SecurityCriticalAttribute или если он находится в сборке, критической с точки зрения безопасности. Начиная с версии NET Framework 4 в отношении доступа к членам, критически важным с точки зрения безопасности, применяются описанные ниже правила.

  • Прозрачный код не может использовать отражение для доступа к членам, критическим с точки зрения безопасности, даже если он является полностью доверенным. Создается исключение MethodAccessException, FieldAccessException или TypeAccessException.

  • Код, выполняемый с частичным доверием, рассматривается как прозрачный.

Эти правила являются одинаковыми как для прямого доступа к члену, критическому с точки зрения безопасности, из скомпилированного кода, так и для доступа с помощью отражения.

Код приложения, который запускается из командной строки, выполняется с полным доверием. Если код не помечен как прозрачный, он может использовать отражение для доступа к членам, критическим с точки зрения безопасности. При выполнении того же кода с частичным доверием (например, в изолированном домене приложения) уровень доверия сборки определяет, может ли она получить доступ к коду, критическому с точки зрения безопасности: если сборка имеет строгое имя и установлена в глобальном кэше сборок, она является доверенной и может вызывать члены, критические с точки зрения безопасности. Если код не является доверенным, он становится прозрачным даже в том случае, если не был помечен как прозрачный, и не может получить доступ к членам, критическим с точки зрения безопасности.

Отражение и прозрачность

Начиная с версии .NET Framework 4 среда CLR определяет уровень прозрачности типа или члена на основе нескольких факторов, включая уровень доверия сборки и уровень доверия домена приложения. Отражение предоставляет свойства IsSecurityCritical, IsSecuritySafeCritical и IsSecurityTransparent, которые позволяют определить уровень прозрачности типа. В таблице ниже приведены допустимые сочетания этих свойств.

Уровень безопасности IsSecurityCritical IsSecuritySafeCritical IsSecurityTransparent
Критически важно true false false
Критический в плане безопасности true true false
Прозрачный режим false false true

Использовать эти свойства гораздо проще, чем просматривать заметки о безопасности для сборки и ее типов, проверять текущий уровень доверия и пытаться дублировать правила среды выполнения. Например, один и тот же тип может быть критическим с точки зрения безопасности при запуске из командной строки или прозрачным для системы безопасности при запуске в изолированном домене приложения.

Аналогичные свойства имеются в классах MethodBase, FieldInfo, TypeBuilder, MethodBuilder и DynamicMethod. (Для других отражений и абстракций порождаемых отражений атрибуты безопасности применяются к связанным методам; например, в случае свойств они применяются к методам доступа к свойствам).

Доступ к обычно недоступным членам

Чтобы использовать отражение для вызова членов, которые недоступны в соответствии с правилами доступности среды CLR, коду необходимо предоставить одно из двух разрешений.

  • Чтобы разрешить коду вызывать любой закрытый член, ему нужно предоставить разрешение ReflectionPermission с флагом ReflectionPermissionFlag.MemberAccess.

    Примечание.

    По умолчанию политика безопасности отказывает в предоставлении этого разрешения коду, полученному из Интернета. Это разрешение ни в коем случае нельзя предоставлять коду, источником которого является Интернет.

  • Чтобы разрешить коду вызывать любой закрытый член, только если набор прав сборки, содержащей вызываемый член, идентичен набору прав сборки, содержащей вызывающий код, или является его подмножеством, коду необходимо предоставить разрешение ReflectionPermission с флагом ReflectionPermissionFlag.RestrictedMemberAccess.

Предположим, вы предоставляете домену приложения разрешения на доступ к Интернету плюс разрешение ReflectionPermission с флагом ReflectionPermissionFlag.RestrictedMemberAccess, а затем запускаете веб-приложение с двумя сборками, A и B.

  • Сборка A может использовать отражение для доступа к закрытым членам сборки B, так как набор прав сборки B не включает какие-либо разрешения, которые не предоставлены сборке A.

  • Сборка A не может использовать отражение для доступа к закрытым членам сборок платформы .NET Framework, таких как mscorlib.dll, так как mscorlib.dll является полностью доверенной и поэтому обладает разрешениями, которые не были предоставлены сборке A. Возникает исключение MemberAccessException, когда управление доступом для кода выполняет обход стека в среде выполнения.

Сериализация

Что касается сериализации, разрешение SecurityPermission с флагом SecurityPermissionAttribute.SerializationFormatter предоставляет возможность получать и задавать члены сериализуемых типов независимо от доступности. Это разрешение позволяет коду обнаруживать и изменять закрытое состояние экземпляра. (Помимо наличия соответствующих разрешений тип должен быть помечен как сериализуемый в метаданных.)

Параметры типа MethodInfo

Избегайте написания открытых членов, принимающих параметры MethodInfo, особенно для доверенного кода. Такие члены могут оказаться более уязвимыми для вредоносного кода. Например, рассмотрим открытый член в коде с высоким уровнем доверия, принимающий параметр MethodInfo. Предположим, что открытый член косвенно вызывает метод Invoke для предоставленного параметра. Если открытый член не выполняет необходимые проверки разрешений, вызов метода Invoke всегда будет успешным, так как система безопасности определяет, что вызывающий объект является полностью доверенным. Даже если вредоносный код не имеет разрешения на прямой вызов метода, он по-прежнему может сделать это косвенным образом, вызвав открытый член.

Сведения о версии

  • Начиная с NET Framework 4 прозрачный код не может использовать отражение для доступа к членам, критически важным с точки зрения безопасности.

  • Флаг ReflectionPermissionFlag.RestrictedMemberAccess впервые появился в .NET Framework 2.0 с пакетом обновления 1 (SP1). Более ранние версии платформы .NET Framework требуют флаг ReflectionPermissionFlag.MemberAccess для кода, который использует отражение для доступа к закрытым членам. Это разрешение, которое ни в коем случае нельзя предоставлять коду с частичным доверием.

  • Начиная с платформа .NET Framework 2.0, использование отражения для получения сведений о типах неопубликованных и членов не требует каких-либо разрешений. В более ранних версиях для этого требовалось разрешение ReflectionPermission с флагом ReflectionPermissionFlag.TypeInformation.

См. также