Использование метода Assert
Assert — это метод, который может вызываться для классов разрешений доступа к коду и класса PermissionSet. Метод Assert может использоваться для обеспечения возможности выполнения кодом (и вышестоящими вызывающими объектами) действий, разрешение на выполнение которых имеется у кода, но может отсутствовать у вызывающих его объектов. Утверждение безопасности изменяет ход процесса, выполняемого средой выполнения при проверке безопасности. При утверждении разрешения, оно сообщает системе безопасности о том, что не следует проверять вызывающие объекты вашего кода на наличие затребованного разрешения.
![]() |
---|
При использовании утверждений безопасности следует соблюдать осторожность, поскольку они могут открывать бреши в системе безопасности и подрывать работу механизма среды выполнения по обеспечению выполнения ограничений безопасности. |
Утверждения полезны в ситуациях, когда библиотека вызывает неуправляемый код или совершает вызов, требующий разрешения, не связанного явно с назначением библиотеки. Например, любой управляемый код, вызывающий неуправляемый код, должен обладать разрешением SecurityPermission с указанным флагом UnmanagedCode. Код, не исходящий от локального компьютера, например, код, загруженный из локальной интрасети, по умолчанию не получит этого разрешения. Таким образом, чтобы код, загруженный из локальной интрасети, мог вызывать библиотеку, использующую неуправляемый код, он должен обладать разрешением, утверждаемым библиотекой. Кроме того, некоторые библиотеки могут выполнять вызовы, которые не видны вызывающим объектам и требуют специальных разрешений.
Можно также использовать утверждения в ситуациях, когда ваш код осуществляет доступ к ресурсу способом, полностью скрытым от вызывающих объектов. Предположим, что ваша библиотека получает информацию из базы данных, но попутно также считывает информацию из реестра компьютера. Так как разработчики, использующие вашу библиотеку, не имеют доступа к ее исходному коду, они не могут знать, что их код обязан иметь разрешение RegistryPermission, чтобы пользоваться вашим кодом. В этом случае, если вы сочтете необоснованным или необязательным требовать от вызывающих объектов вашего кода разрешений на доступ к реестру, вы можете утвердить разрешение на чтение из реестра. В этой ситуации утверждение разрешения библиотекой оправдано, поскольку обеспечивает возможность использования библиотеки вызывающими объектами, не имеющими разрешения RegistryPermission.
Утверждение влияет на проверку стека только в случае, когда утверждаемое разрешение и разрешение, затребованное вызываемым объектом, имеют один и тот же тип, либо когда затребованное разрешение является подмножеством утверждаемого. Например, если вы утверждаете разрешение FileIOPermission на чтение любых файлов с диска C, а последующее требование запрашивает разрешение FileIOPermission на чтение файлов из папки C:\\Temp, утверждение может повлиять на проверку стека; однако если было затребовано разрешение FileIOPermission для записи на диск C, утверждение не принесет никакого эффекта.
Для выполнения утверждений коду должно быть дано как утверждаемое разрешение, так и разрешение SecurityPermission, предоставляющее право на выполнение утверждений. Хотя и существует возможность утверждения разрешения, отсутствующего у кода, это утверждение будет бессмысленным, так как проверка безопасности потерпит неудачу раньше, чем утверждение могло бы заставить ее завершиться успешно.
Следующая иллюстрация показывает, что происходит при использовании метода Assert. Предположим, что для сборок A, B, C, E и F, а также разрешений P1 и P1A верны следующие утверждения.
P1A предоставляет право чтения TXT-файлов на диске C.
P1 предоставляет право чтения любых файлов на диске C.
P1A и P1 имеют тип FileIOPermission , а P1A — подмножество P1.
Сборки E и F обладают разрешением P1A.
Сборка C обладает разрешением P1.
Сборки A и B не имеют ни разрешения P1, ни разрешения P1A.
Метод A содержится в сборке A, метод B содержится в сборке В и так далее.
Использование метода Assert
В данном сценарии метод A вызывает B, В вызывает C, C вызывает E, E вызывает F. Метод C проверяет разрешение на чтение файлов на диске C (разрешение P1), а метод E требует разрешения на чтение TXT-файлов на диске C (разрешение P1A). Когда требование из F обнаруживается во время выполнения, выполняется проход по стеку для проверки разрешений всех вызывающих объектов F, начиная с E. E имеет разрешение P1A, поэтому проход по стеку продолжается для проверки разрешений у C, где обнаруживается проверка для C. Так как затребованное разрешение (P1A) является подмножеством утверждаемого (P1), проверка стека останавливается и проверка безопасности завершается успешно. Отсутствие у сборок A и B разрешения P1A не имеет значения. Утверждая P1, метод C обеспечивает своим вызывающим объектам возможность доступа к ресурсу, защищенному P1, даже если вызывающие объекты не обладают правом доступа к этому ресурсу.
Если разрабатывается библиотека классов и класс осуществляет доступ к защищенному ресурсу, в большинстве случаев следует произвести требование безопасности, требующее от вызывающих объектов класса соответствующего разрешения. Если после этого класс выполняет операцию, о которой известно, что большинство ее вызывающих объектов не будут иметь для нее разрешения, и требуется принять ответственность за предоставление этим вызывающим объектам возможности вызова вашего кода, можно утвердить это разрешение, вызывая метод Assert для объекта разрешения, предоставляющего операцию, выполняемую кодом. Использование Assert в таком виде дает возможность вызывать ваш код вызывающим объектам, которые в обычных условиях не могли бы этого сделать. Таким образом, если вы утверждаете разрешение, вы должны непременно заранее выполнить соответствующие проверки безопасности, чтобы предотвратить ваш компонент от использования не по назначению.
Например, предположим, что высоко доверенный класс библиотеки содержит метод удаления файлов. Он осуществляет доступ к файлу через неуправляемую функцию Win32. Вызывающий объект вызывает метод Delete кода, передавая имя подлежащего удалению файла, C:\\Test.txt. В методе Delete код создает объект FileIOPermission, предоставляющий доступ с правом записи в файл C:\\Test.txt. (Для удаления файла требуется доступ на запись.) Затем код инициирует явный запрос разрешений, вызывая метод Demand объекта FileIOPermission. Если один из вызывающих объектов в стеке вызовов не имеет этого разрешения, создается исключение SecurityException. Если исключения не создается, становится понятно, что все вызывающие объекты имеют право доступа к файлу C:\\Test.txt. Поскольку теперь известно, что большинство вызывающих объектов не будут иметь разрешения на доступ к неуправляемому коду, код создает объект SecurityPermission, предоставляющий право вызова неуправляемого кода, и вызывает метод Assert этого объекта. В конце концов, он вызывает неуправляемую функцию Win32 для удаления файла C:\Test.txt и возвращает управление вызывающему объекту.
![]() |
---|
Необходимо убедиться, что код не использует утверждения в ситуациях, когда он может быть использован другим кодом для осуществления доступа к ресурсу, защищенному утверждаемым разрешением.Например, в коде, производящем запись в файл, имя которого указывается вызывающим объектом как параметр, не следует утверждать FileIOPermission на запись, так как в этом случае код становится открытым для использования посторонним кодом не по назначению. |
При использовании принудительного синтаксиса безопасности вызов метода Assert для нескольких разрешений в одном методе приведет к созданию исключения безопасности. Вместо этого необходимо создать объект PermissionSet, передать ему отдельные разрешения, которые необходимо вызвать, а затем вызвать метод Assert для объекта PermissionSet. При использовании декларативного синтаксиса безопасности метод Assert можно вызывать несколько раз.
Следующий пример демонстрирует декларативный синтаксис переопределения проверок безопасности с использованием метода Assert. Обратите внимание, что синтаксис FileIOPermissionAttribute принимает два значения: перечисление SecurityAction и местоположение файла или папки, разрешение на который будет выдаваться. Вызов Assert приводит к удовлетворению требований на доступ к файлу C:\Log.txt, хотя вызывающие объекты не проверяются на наличие разрешений на запись в этот файл.
[Visual Basic]
Option Explicit
Option Strict
Imports System
Imports System.IO
Imports System.Security.Permissions
Namespace LogUtil
Public Class Log
Public Sub New()
End Sub
<FileIOPermission(SecurityAction.Assert, All := "C:\Log.txt")> Public Sub
MakeLog()
Dim TextStream As New StreamWriter("C:\Log.txt")
TextStream.WriteLine("This Log was created on {0}", DateTime.Now) '
TextStream.Close()
End Sub
End Class
End Namespace
namespace LogUtil
{
using System;
using System.IO;
using System.Security.Permissions;
public class Log
{
public Log()
{
}
[FileIOPermission(SecurityAction.Assert, All = @"C:\Log.txt")]
public void MakeLog()
{
StreamWriter TextStream = new StreamWriter(@"C:\Log.txt");
TextStream.WriteLine("This Log was created on {0}", DateTime.Now);
TextStream.Close();
}
}
}
Следующие примеры демонстрируют явный синтаксис переопределения проверок безопасности с использованием метода Assert. В этом примере объявляется экземпляр объекта FileIOPermission. Его конструктору передается параметр FileIOPermissionAccess.AllAccess для установки типа открываемого доступа, со строкой, описывающей местоположение файла. Как только объект FileIOPermission определен, нужно только вызвать его метод Assert для переопределения проверки безопасности.
[Visual Basic]
Option Explicit
Option Strict
Imports System
Imports System.IO
Imports System.Security.Permissions
Namespace LogUtil
Public Class Log
Public Sub New()
End Sub 'New
Public Sub MakeLog()
Dim FilePermission As New FileIOPermission(FileIOPermissionAccess.AllAccess, "C:\Log.txt")
FilePermission.Assert()
Dim TextStream As New StreamWriter("C:\Log.txt")
TextStream.WriteLine("This Log was created on {0}", DateTime.Now)
TextStream.Close()
End Sub
End Class
End Namespace
namespace LogUtil
{
using System;
using System.IO;
using System.Security.Permissions;
public class Log
{
public Log()
{
}
public void MakeLog()
{
FileIOPermission FilePermission = new FileIOPermission(FileIOPermissionAccess.AllAccess,@"C:\Log.txt");
FilePermission.Assert();
StreamWriter TextStream = new StreamWriter(@"C:\Log.txt");
TextStream.WriteLine("This Log was created on {0}", DateTime.Now);
TextStream.Close();
}
}
}
См. также
Ссылки
Основные понятия
Расширение метаданных с помощью атрибутов