Практическое руководство. Запрос минимальных разрешений с помощью флага RequestMinimum
Важно!
В версии .NET Framework 4 удалена поддержка среды выполнения для принудительного применения запросов разрешений Deny, RequestMinimum, RequestOptional и RequestRefuse.Эти запросы нельзя использовать в коде, основанном на .NET Framework 4 или более поздних версиях.Дополнительные сведения об этом и других изменениях см. в разделе Изменения системы безопасности в платформе .NET Framework 4.
Флаг RequestMinimum позволяет запрашивать минимальный набор разрешений, необходимый для выполнения кода.Флаг RequestRefuse, напротив, позволяет отклонять разрешения, явно указывая, какие из них не должны выдаваться коду.
Для запроса разрешений можно также использовать флаг RequestOptional.В этом случае приложение будет выполняться, даже если им не получены все запрошенные разрешения. Однако при попытке приложения получить доступ к защищенному ресурсу создается исключение SecurityException.Если используется этот тип запроса, необходимо обеспечить в коде перехват всех исключений, которые будут созданы, если коду не будут предоставлены необязательные разрешения.
В примере Test из нижеследующей процедуры запрашивается разрешение FileIOPermission с помощью флага RequestMinimum.Пример не будет выполняться, если ему не будет предоставлено запрошенное разрешение.По умолчанию при запуске примера на настольном компьютере ему предоставляется полное доверие, и поэтому он всегда выполняется.Для проверки флага RequestMinimum необходимо загрузить пример в частично доверенную зону, которая не предоставляет разрешение FileIOPermission.В представленной ниже процедуре создается "песочница" для зоны LocalIntranet и тестовое приложение, которому требуется разрешение FileIOPermission.Для демонстрации использования флага RequestMinimum тестовое приложение запускается в "песочнице".После загрузки приложения создается исключение.
Запуск приложения в "песочнице"
Создайте проект консольного приложения в Visual Studio.
Скопируйте код из раздела Пример в файл приложения.Этот код создает "песочницу", выполняемую с набором разрешений LocalIntranet.Набор разрешений LocalIntranet не включает разрешение FileIOPermission.
В меню Проект щелкните пункт Свойства, перейдите на вкладку Подписывание и подпишите проект ключом строго имени.
Добавьте в решение новый проект консольного приложения с именем Test.
Скопируйте следующий код в файл приложения для проекта Test.В этом коде запрашивается разрешение FileIOPermission в качестве минимального требования.Если это разрешение не может быть предоставлено, создается исключение SecurityException.
Imports System Imports System.Security.Permissions Imports System.IO <Assembly: FileIOPermission(SecurityAction.RequestMinimum, Unrestricted:=True)> Namespace Test Class Program Shared Sub Main(ByVal args() As String) Console.WriteLine("Test is loaded.") File.Create("test.txt") End Sub 'Main End Class 'Program End Namespace
using System; using System.Security.Permissions; using System.IO; [assembly: FileIOPermission(SecurityAction.RequestMinimum, Unrestricted=true)] namespace Test { class Program { static void Main(string[] args) { Console.WriteLine("Test is loaded."); File.Create("test.txt"); } } }
Запустите приложение "песочницы".Оно предпримет попытку загрузить и запустить тестовое приложение.После загрузки приложения создается исключение со следующим сообщением:
Could not load file or assembly 'Test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies.Failed to grant minimum permission requests.(Exception from HRESULT: 0x80131417)":"Test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"}.
Удалите требование RequestMinimum, удалив соответствующую строку или пометив ее комментарием.Пример будет загружен и начнется его выполнение, однако создается исключение со следующим сообщением:
Request for the permission of type 'System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed.
Используя флаг RequestMinimum, можно запретить загрузку приложения, выполнение которого заведомо завершится неудачей.Дополнительные сведения о запуске приложений в "песочнице" см. в разделе Практическое руководство. Выполнение не вполне безопасного кода в изолированной среде.
Пример
В следующем примере создается "песочница", выполняемая с набором разрешений LocalIntranet.
Imports System
Imports System.Collections
Imports System.Diagnostics
Imports System.Security
Imports System.Security.Permissions
Imports System.Security.Policy
Imports System.Reflection
Imports System.IO
Class Program
Shared Sub Main(ByVal args() As String)
' Create the permission set to grant to other assemblies.
' In this case we are granting the permissions found in the LocalIntranet zone.
Dim e As New Evidence()
e.AddHostEvidence(New Zone(SecurityZone.Intranet))
Dim pset As PermissionSet = SecurityManager.GetStandardSandbox(e)
' Optionally you can create your own permission set by explicitly adding permissions.
' PermissionSet pset = new PermissionSet(PermissionState.None);
' pset.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
' pset.AddPermission(new UIPermission(PermissionState.Unrestricted));
Dim ads As New AppDomainSetup()
' Identify the folder to use for the sandbox.
ads.ApplicationBase = "C:\Sandbox"
' Copy the application to be executed to the sandbox.
File.Copy("..\..\..\HelloWorld\Bin\Debug\HelloWorld.exe", "C:\sandbox\HelloWorld.exe", True)
Dim hostEvidence As New Evidence()
' Commenting out the following statement has no effect on the sample.
' The grant set is determined by the grantSet parameter, not the evidence
' for the assembly. However, the evidence can be used for other reasons,
' for example, isolated storage.
hostEvidence.AddHostEvidence(New Zone(SecurityZone.Intranet))
' Create the sandboxed domain.
' You can replace the null parameter with a strong name that identifies full trust assemblies:
' GetStrongName(Assembly.GetExecutingAssembly())); This identifies any assemblies in the folder
' that are signed with the same strong name as this assembly as being full trust assemblies.
Dim sandbox As AppDomain = AppDomain.CreateDomain("Sandboxed Domain", hostEvidence, ads, pset, Nothing)
sandbox.ExecuteAssemblyByName("HelloWorld")
End Sub 'Main
Public Shared Function GetStrongName(ByVal [assembly] As [Assembly]) As StrongName
If [assembly] Is Nothing Then
Throw New ArgumentNullException("assembly")
End If
Dim assemblyName As AssemblyName = [assembly].GetName()
Debug.Assert(Not (assemblyName Is Nothing), "Could not get assembly name")
' Get the public key blob.
Dim publicKey As Byte() = assemblyName.GetPublicKey()
If publicKey Is Nothing OrElse publicKey.Length = 0 Then
Throw New InvalidOperationException("Assembly is not strongly named")
End If
Dim keyBlob As New StrongNamePublicKeyBlob(publicKey)
' Return the strong name.
Return New StrongName(keyBlob, assemblyName.Name, assemblyName.Version)
End Function 'GetStrongName
End Class 'Program
using System;
using System.Collections;
using System.Diagnostics;
using System.Security;
using System.Security.Permissions;
using System.Security.Policy;
using System.Reflection;
using System.IO;
namespace SimpleSandboxing
{
class Program
{
static void Main(string[] args)
{
// Create the permission set to grant to other assemblies.
// In this case we are granting the permissions found in the LocalIntranet zone.
Evidence e = new Evidence();
e.AddHostEvidence(new Zone(SecurityZone.Intranet));
PermissionSet pset = SecurityManager.GetStandardSandbox(e);
// Optionally you can create your own permission set by explicitly adding permissions.
// PermissionSet pset = new PermissionSet(PermissionState.None);
// pset.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
// pset.AddPermission(new UIPermission(PermissionState.Unrestricted));
AppDomainSetup ads = new AppDomainSetup();
// Identify the folder to use for the sandbox.
ads.ApplicationBase = "C:\\Sandbox";
// Copy the application to be executed to the sandbox.
File.Copy("..\\..\\..\\HelloWorld\\Bin\\Debug\\HelloWorld.exe", "C:\\sandbox\\HelloWorld.exe", true);
Evidence hostEvidence = new Evidence();
// Commenting out the following statement has no effect on the sample.
// The grant set is determined by the grantSet parameter, not the evidence
// for the assembly. However, the evidence can be used for other reasons,
// for example, isolated storage.
hostEvidence.AddHostEvidence(new Zone(SecurityZone.Intranet));
// Create the sandboxed domain.
// You can replace the null parameter with a strong name that identifies full trust assemblies:
// GetStrongName(Assembly.GetExecutingAssembly())); This identifies any assemblies in the folder
// that are signed with the same strong name as this assembly as being full trust assemblies.
AppDomain sandbox = AppDomain.CreateDomain(
"Sandboxed Domain",
hostEvidence,
ads,
pset,
null); // Optionally: GetStrongName(Assembly.GetExecutingAssembly()));
sandbox.ExecuteAssemblyByName("HelloWorld");
}
public static StrongName GetStrongName(Assembly assembly)
{
if (assembly == null)
throw new ArgumentNullException("assembly");
AssemblyName assemblyName = assembly.GetName();
Debug.Assert(assemblyName != null, "Could not get assembly name");
// Get the public key blob.
byte[] publicKey = assemblyName.GetPublicKey();
if (publicKey == null || publicKey.Length == 0)
throw new InvalidOperationException("Assembly is not strongly named");
StrongNamePublicKeyBlob keyBlob = new StrongNamePublicKeyBlob(publicKey);
// Return the strong name.
return new StrongName(keyBlob, assemblyName.Name, assemblyName.Version);
}
}
}