Симон Робинсон - C# для профессионалов. Том II
При выполнении caspol.exe администратором по умолчанию используется уровень машины, но если выйти из системы и зарегистрироваться как пользователь, который не принадлежит группе пользователей Administrator, caspol.exe выберет по умолчанию уровень пользователя. Кроме того, caspol.exe не позволит изменить политику безопасности таким образом, чтобы сделать саму утилиту caspol.exe неработоспособной.
Теперь мы получили общее представление об архитектуре безопасности в .NET и можем перейти к обсуждению, как получить доступ к ее свойствам программным путем.
Поддержка безопасности в .NET
Чтобы система безопасности .NET работала, программистам необходимо доверить CLR обеспечение политики безопасности. Как это сделать? Когда вызывается метод, требующий специальных полномочий (например, доступ к файлу на локальном диске), CLR будет просматривать стек с целью гарантии того, что участник цепочки вызовов имеет требуемые права.
Слово 'производительность' уже, вероятно, обеспокоило вас в данный момент, и понятно, что ее повышение — это проблема, но чтобы получить преимущества управляемой среды .NET, приходится платить за безопасность. Иначе сборки, не являющиеся полностью надежны ни, могли бы делать обращения к надежным сборкам и система была бы открыта для атаки.
Для справки, наиболее применимыми в этой главе частями библиотеки .NET Framework являются:
□ System.Security.Permissions
□ System.Security.Policy
□ System.Security.Principal
Отметим, что система безопасности доступа к коду на основе свидетельства работает в паре с системой безопасности регистрации в Windows. Если вы захотите выполнить приложение для настольного компьютера .NET, то ему должны быть предоставлены соответствующие полномочия системы безопасности доступа к коду .NET, но регистрирующийся пользователь должен также работать под учетной записью Windows, которая имеет соответствующие права для выполнения кода. В применении к настольным приложениям это означает, что текущему пользователю должны быть предоставлены соответствующие права для доступа к соответствующим файлам сборки на диске. Для приложений Интернета учетная запись, с которой работает Информационный сервер Интернет, должна иметь доступ к файлам сборки.
Требуемые полномочия
Создадим приложение Windows Forms с кнопкой, которая при нажатии будет выполнять действие, обращающееся к диску. Предположим, что если приложение не имеет подходящего полномочия для доступа к локальному диску (FileIOPermission), кнопка будет помечаться как недоступная (серым цветом).
В следующем коде представлен конструктор формы, который создает объект FileIOPermission, вызывает его метод Demand() и затем обрабатывают результат:
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Security;
using System.Security.Permissions;
namespace SecurityApp4 {
public class Form1 : System.Windows.Forms.Form {
private System.Windows.Forms.Button button1;
private System.ComponentModel.Container components;
public Form1() {
InitializeComponent();
try {
FileIOPermission fileioperm = new
FileIOPermission(FileIOPermissionAccess.AllAccess, @"C:");
fileioperm.Demand();
} catch {
button1.Enabled = false;
}
}
public override void Dispose() {
base.Dispose();
if(component != null) components.Dispose();
}
#region Windows Form Designer generated code
/// <summary>
/// Требуемый метод для поддержки конструктора — не изменяйте
/// содержимое этого метода с помощью редактора кода.
/// </summary >
private void InitializeComponent() {
this.button1 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(48, 104);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(192, 23);
this.button1.TabIndex = 0;
this.button1.Text = "Button Requires FileIOPermission";
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(292, 273);
this.Controls.AddRange(new System.Windows.Forms.Control[] {this.button1});
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
}
#endregion
/// <summary>
/// Основная точка входа для приложения.
/// </summary >
[STAThread]
static void Main() {
Application.Run(new Form1());
}
}
}
Можно заметить, что FileIOPermission содержится в пространстве имен System.Security.Permissions, которое имеет все множество полномочий, а также предоставляет классы для декларативных атрибутов полномочий и перечисления параметров, используемых при создании объектов прав (например, при создании FileIOPermission, определяющего, нужен нам полный доступ или только для чтения).
При выполнении приложения с локального диска, где используемая по умолчанию политика безопасности разрешает доступ к локальной памяти, приложение будет выглядеть следующим образом:
Но если скопировать исполняемый файл на сетевой диск общего доступа и снова его выполнить, то он будет действовать внутри множества полномочий LocalIntranet, которое блокирует доступ к локальной памяти, и кнопка будет неработоспособной (серой):
Если при нажатии на кнопку была реализована функциональность для доступа к диску, не требуется писать никакой код для системы безопасности, так как соответствующий класс в .NET Framework будет запрашивать полномочия файла и CLR гарантирует, что каждый вызывающий в стеке будет иметь эти полномочия, прежде чем продолжить. При выполнении приложения из интранет, которое пытается открыть файл на локальном диске, будет порождаться исключение при условии, что политика безопасности не была изменена.
При желании перехватывать исключения, порождаемые CLR, когда код пытается действовать вопреки предоставленным ему правам, можно перехватывать исключение типа SecurityException, которое предоставляет доступ к ряду полезных элементов информации, включая читаемую человеком трассировку стека (SecurityException.StackTrace) и ссылку на метод, порождающий исключение (SecurityException.TargetSite). SecurityException предоставляет также свойство SecurityException.PermissionType, возвращающее тип объекта Permission, который порождает исключения безопасности.
Запрашиваемые полномочия
Как мы видели выше, требуемые полномочия вполне четко определяют, что необходимо во время выполнения, однако можно сконфигурировать сборку так, чтобы она делала более мягкий запрос прав прямо в начале выполнения, где она объявляет, что ей нужно: Можно запросить полномочия тремя способами:
□ Минимальные полномочия (Mimimum) — полномочия, которые требуются коду для выполнения.
□ Необязательные полномочия (Optional) — полномочия, которые код может использовать, но способен эффективно выполняться и без них.
□ Непригодные полномочия (Refused) — полномочия, которые не должны предоставляться коду.
Почему необходимо запрашивать полномочия при запуске сборки? Существует несколько причин:
□ Если сборке требуются некоторые полномочия для выполнения, то имеет смысл сообщить об этом в начале, а не во время выполнения.
□ Будут предоставлены только запрашиваемые полномочия и никакие другие. Это сокращает риск воздействия сборки на области, для которых у нее нет прав.
□ Если запрашивается минимальный набор полномочий, увеличивается вероятность того, что сборка будет выполнена.
Запрос полномочий скорее всего будет тем нужнее, чем более сложная разработка реализуется, но существует высокий риск, что приложение будет установлено на машине, которая не предоставляет необходимых прав. Обычно для приложения более предпочтительно знать в самом начале выполнения, где ему не предоставлены полномочия, а не в середине процесса выполнения.
Чтобы успешно запрашивать полномочия для сборки, нужно точно отслеживать, какие права использует сборка. В частности, необходимо знать о требованиях полномочий вызовов, которые делает сборка в других библиотеках классов, включая .NET Framework.
Три примера из файла AssemblyInfo.cs (см. ниже) демонстрируют использование атрибутов для запроса полномочий. Эти примеры можно найти в проекте SecurityАрр9 среди загружаемых с сайта издательства Wrox файлов. Первый атрибут выдвигает требование, чтобы сборка имела UIPermission, что даст приложению доступ к интерфейсу пользователя. Запрос делается для минимальных полномочий, а если это право не предоставляется, то сборка не сможет запуститься.