Вопросы безопасности в порождении отражения

платформа .NET Framework предоставляет три способа выдачи общего промежуточного языка (CIL), каждый из которых имеет собственные проблемы безопасности:

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

Примечание.

Разрешения, необходимые для отражения и порождения кода, были изменены в последующих выпусках .NET Framework. См. сведения о версии далее в этой статье.

Динамические сборки

Динамические сборки создаются с помощью перегрузок метода AppDomain.DefineDynamicAssembly. Большинство способов перегрузки этого метода не рекомендуется использовать в .NET Framework 4, так как политика безопасности на уровне компьютера больше не используется. Остальные перегрузки могут выполняться из любого кода независимо от уровня доверия. Эти перегрузки делятся на две группы: те, которые определяют список атрибутов, применяемых к динамической сборке при ее создании, и те, которые этого не делают. Если не указать модель прозрачности для сборки, применив атрибут SecurityRulesAttribute при ее создании, эта модель наследуется от порождающей сборки.

Примечание.

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

Код в динамической сборке может получать доступ к видимым типам и членам в других сборках.

Примечание.

Динамические сборки не используют флаги ReflectionPermissionFlag.MemberAccess и ReflectionPermissionFlag.RestrictedMemberAccess, разрешающие динамическим методам получать доступ к закрытым типам и членам.

Временные динамические сборки создаются в памяти и никогда не сохраняются на диск, поэтому им не требуются разрешения на доступ к файлам. Для сохранения динамической сборки на диск требуется разрешение FileIOPermission с соответствующими флагами.

Создание динамических сборок из частично доверенного кода

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

  • Динамическая сборка использует только открытые типы и члены других сборок.

  • Разрешения, необходимые для этих типов и членов, включаются в набор прав сборки с частичным доверием.

  • Сборка не сохраняется на диск.

  • Отладочные символы не создаются (наборы разрешений Internet и LocalIntranet не включают необходимые разрешения).

Анонимно размещенные динамические методы

Анонимно размещенные динамические методы создаются с помощью двух конструкторов DynamicMethod, которые не указывают связанный тип или модуль, DynamicMethod(String, Type, Type[]) и DynamicMethod(String, Type, Type[], Boolean). Эти конструкторы размещают динамические методы в предоставляемой системой сборке, которая является полностью доверенной и прозрачный для системы безопасности. Для использования этих конструкторов или порождения кода для динамических методов разрешения не требуются.

Вместо этого при создании анонимно размещаемых динамических методов записывается стек вызовов. При создании метода требования безопасности предъявляются к записанному стеку вызовов.

Примечание.

Концептуально требования предъявляются во время создания метода. То есть требования могут быть сделаны по мере выдачи каждой инструкции CIL. В текущей реализации все требования предъявляются при вызове метода DynamicMethod.CreateDelegate или JIT-компилятора, если метод вызывается без вызова CreateDelegate.

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

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

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

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

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

Системная сборка, в которой размещаются анонимно размещенные динамические методы, использует модель прозрачности SecurityRuleSet.Level1, то есть модель, которая применялась в .NET Framework до версии .NET Framework 4.

Дополнительные сведения см. в описании класса DynamicMethod.

Создание анонимно размещенных динамических методов из частично доверенного кода

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

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

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

Примечание.

Динамические методы не поддерживают отладочные символы.

Динамические методы, связанные с существующими сборками

Чтобы связать динамический метод с типом или модулем в существующей сборке, используйте любой из конструкторов DynamicMethod, который указывает связанный тип или модуль. Разрешения, необходимые для вызова этих конструкторов, могут быть разными, так как при связывании динамического метода с существующим типом или модулем он получает доступ к закрытым типам и членам.

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

  • Динамический метод, связанный с модулем, имеет доступ ко всем типам и членам internal (Friend в Visual Basic, assembly в метаданных среды CLR) в модуле.

Кроме того, можно использовать конструктор, который задает возможность пропускать проверки видимости JIT-компилятора. Это позволяет динамическому методу получать доступ ко всем типам и членам во всех сборках независимо от уровня доступа.

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

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

  • Если вы указываете, что проверки видимости JIT-компилятора следует пропустить, конструктору требуется разрешение ReflectionPermission с флагом ReflectionPermissionFlag.MemberAccess.

  • Если динамический метод связывается с другим типом, даже с типом из вашей собственной сборки, конструктору требуется разрешение ReflectionPermission с флагом ReflectionPermissionFlag.MemberAccess и разрешение SecurityPermission с флагом SecurityPermissionFlag.ControlEvidence.

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

    Примечание.

    В целях обратной совместимости, если не удается удовлетворить потребность в целевом наборе прав и разрешении ReflectionPermissionFlag.RestrictedMemberAccess, конструктору требуется разрешение SecurityPermission с флагом SecurityPermissionFlag.ControlEvidence.

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

Дополнительные сведения см. в описании класса DynamicMethod.

Создание динамических методов из частично доверенного кода

Примечание.

Рекомендуемый способ создания динамических методов из частично доверенного кода — использовать анонимные динамические методы.

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

  • Либо динамический метод связан с порождающим его модулем или типом, либо его набор прав включает ReflectionPermissionFlag.RestrictedMemberAccess и он связан с модулем в сборке, набор прав которой идентичен набору прав порождающей сборки или является его подмножеством.

  • Динамический метод использует только открытые типы и члены. Если его набор прав включает ReflectionPermissionFlag.RestrictedMemberAccess и он связан с модулем в сборке, набор прав которой идентичен набору прав порождающей сборки или является его подмножеством, он может использовать типы и члены, помеченные как internal (Friend в Visual Basic, assembly в метаданных среды CLR) в связанном модуле.

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

  • Динамический метод не пропускает проверки видимости JIT-компилятора.

Примечание.

Динамические методы не поддерживают отладочные символы.

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

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

Начиная с .NET Framework 2.0 с пакетом обновления 1 (SP1), разрешение ReflectionPermission с флагом ReflectionPermissionFlag.ReflectionEmit больше не требуется при порождении динамических сборок и динамических методов. Этот флаг необходим во всех более ранних версиях платформы .NET Framework.

Примечание.

Разрешение ReflectionPermission с флагом ReflectionPermissionFlag.ReflectionEmit включается по умолчанию в именованные наборы разрешений FullTrust и LocalIntranet, но не в набор разрешений Internet. Таким образом, в более ранних версиях платформы .NET Framework библиотеку можно использовать с разрешениями на доступ к Интернету только в том случае, если она выполняет Assert для ReflectionEmit. Такие библиотеки требуют тщательной проверки безопасности, так как ошибки в коде могут стать причиной уязвимости. Платформа .NET Framework 2.0 с пакетом обновления 1 (SP1) позволяет создавать код в сценариях частичного доверия без предъявления каких-либо требований к безопасности, так как создание кода по сути не является привилегированной операцией. То есть созданный код имеет не больше разрешений, чем породившая его сборка. Это позволяет библиотекам, порождающим код, сохранять прозрачность для системы безопасности, что устраняет необходимость в утверждении перечисления ReflectionEmit и упрощает задачу написания безопасной библиотеки.

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

Наконец, в .NET Framework 2.0 с пакетом обновления 1 (SP1) реализованы анонимно размещенные методы.

Получение сведений о типах и членах

Начиная с .NET Framework 2.0 для получения сведений о закрытых типах и членах никакие разрешения не требуются. Для получения сведений, необходимых для порождения динамических методов, используется отражение. Например, объекты MethodInfo используются для порождения вызовов метода. Более ранние версии платформы .NET Framework требуют ReflectionPermission с флагом ReflectionPermissionFlag.TypeInformation. Дополнительные сведения см. в разделе Соображения о безопасности для отражения.

См. также