方法 : サンドボックスで部分信頼コードを実行する
更新 : 2007 年 11 月
サンドボックス化は、制限されたセキュリティ環境でアプリケーションを実行する方法です。この方法を採用すると、アプリケーションに付与されるコード アクセス許可が制限されます。たとえば、Internet Explorer にダウンロードされるコントロールは、Internet アクセス許可セットを使用して実行されます。ローカル エリア ネットワークの共有に存在するアプリケーションは、LocalIntranet アクセス許可セットを使用してコンピュータ上で実行されます。これらのアクセス許可の詳細については、「名前付きアクセス許可セット」を参照してください。
サンドボックスを使用して、コンピュータにダウンロードした部分信頼アプリケーションを実行できます。また、イントラネットなどの環境で部分信頼で実行する予定のアプリケーションについて、サンドボックスを使用してテストすることもできます。コード アクセス セキュリティ (CAS: Code Access Security) とサンドボックス化の詳細については、MSDN (Microsoft Developer Network) の「Find Out What's New with Code Access Security in the .NET Framework 2.0」を参照してください。
サンドボックスで実行するアプリケーションのアクセス許可セットを指定するには、CreateDomain(String, Evidence, String, String, Boolean, AppDomainInitializer, array<String[]) メソッド オーバーロードを使用します。このオーバーロードを使用することで、アプリケーションに付与するアクセス許可を指定して、コード アクセス セキュリティのレベルを希望どおりに設定できます。この場合、標準的な CAS ポリシーは使用されません (コンピュータ ポリシーは適用されません)。たとえば、呼び出されたアセンブリが厳密名キーで署名され、その厳密な名前に対してカスタム コード グループが存在する場合、コード グループは適用されません。このオーバーロードを使用して読み込まれるアセンブリには、指定の許可セットのみを付与することもできますし、完全信頼を付与することもできます。グローバル アセンブリ キャッシュに存在するアセンブリ、または完全信頼一覧にあるアセンブリには、完全信頼が付与されます。ただし、完全信頼のアセンブリを対象にする場合は、サンドボックスは使用されません。
オーバーロードは次のシグネチャを持ちます。
AppDomain.CreateDomain( string friendlyName,
Evidence securityInfo,
AppDomainSetup info,
PermissionSet grantSet,
params StrongName[] fullTrustAssemblies);
CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, array<StrongName[]) メソッド オーバーロードのパラメータは、AppDomain の名前、アセンブリの証拠、サンドボックスのアプリケーション ベースを指定する AppDomainSetup オブジェクト、使用するアクセス許可セット、および信頼されたアセンブリの厳密な名前を指定します。
info パラメータに指定するアプリケーション ベースに、ホスト アプリケーションのアプリケーション ベースを指定することはできません。指定すると、ホストされるアセンブリは Load メソッドを使用して、部分信頼の呼び出し元からの呼び出しを検出することを意図されていない他のアセンブリを、該当のフォルダに読み込むことができます。
grantSet パラメータには、明示的に作成したアクセス許可セットを指定するか、Internet、LocalIntranet などのいずれかの名前付きアクセス許可セットを指定します。ここで説明する例では、カスタム アクセス許可セットを作成する方法ではなく、名前付きアクセス許可セットを使用する方法を示します。
他の多くの AppDomain 読み込みとは異なり、許可セットの決定に (securityInfo パラメータで指定される) アセンブリの証拠は使用されません。代わりに、grantSet パラメータによって単独で指定されます。ただし、分離ストレージの決定など、他の用途に証拠を使用できます。
サンドボックスでアプリケーションを実行するには
アプリケーションに付与するアクセス許可セットを作成します。
メモ : この例のアプリケーションでは、実行する Execution アクセス許可と、コンソールに書き込む UIPermission が必要です。次のコードでは、これらのアクセス許可を設定したアクセス許可セットを新しく作成します。別の方法として、LocalIntranet などの既存の名前付きアクセス許可セットを使用することもできます。名前付きアクセス許可セットの使用例については、このトピックの「使用例」を参照してください。
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 you want to run to the sandbox. File.Copy("HelloWorld.exe","C:\\sandbox\\HelloWorld.exe",true);
CreateDomain(String, Evidence, String, String, Boolean, AppDomainInitializer, array<String[]) メソッド オーバーロードを使用してドメインを作成します。ここでは、親アセンブリの証拠と厳密名を指定します。GetStrongName メソッドのコードについては、このトピックの「使用例」を参照してください。
// Create the sandboxed application domain. AppDomain sandbox = AppDomain.CreateDomain( "Sandboxed Domain", AppDomain.CurrentDomain.Evidence, ads, pset, GetStrongName(Assembly.GetExecutingAssembly()));
アプリケーションを実行します。
sandbox.ExecuteAssemblyByName("HelloWorld");
使用例
次に、前のセクションの手順を実装する完全な例を示します。この例は、イントラネット環境で付与されるのと同じアクセス許可セットを使用して、どのようにアプリケーションを実行できるかについて示すものです。この例の HelloWorld.exe アセンブリを置換するには、独自のテスト アプリケーションを作成する必要があります。
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 pset As PermissionSet = GetNamedPermissionSet("LocalIntranet")
If pset Is Nothing Then
Return
End If
' 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.exe", "C:\sandbox\HelloWorld.exe", True)
Dim hostEvidence As New Evidence()
' Commenting out the following two statements 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.AddHost(New Zone(SecurityZone.Intranet))
hostEvidence.AddHost(New Url("C:\Sandbox"))
' Create the sandboxed domain.
Dim sandbox As AppDomain = AppDomain.CreateDomain("Sandboxed Domain", hostEvidence, ads, pset, GetStrongName([Assembly].GetExecutingAssembly()))
sandbox.ExecuteAssemblyByName("HelloWorld")
End Sub 'Main
'' <summary>
'' Get a strong name that matches the specified assembly.
'' </summary>
'' <exception cref="ArgumentNullException">
'' if <paramref name="assembly"/> is null
'' </exception>
'' <exception cref="InvalidOperationException">
'' if <paramref name="assembly"/> does not represent a strongly named assembly
'' </exception>
'' <param name="assembly">Assembly to create a StrongName for</param>
'' <returns>A StrongName for the given assembly</returns>
''
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
Private Shared Function GetNamedPermissionSet(ByVal name As String) As PermissionSet
Dim policyEnumerator As IEnumerator = SecurityManager.PolicyHierarchy()
' Move through the policy levels to the machine policy level.
While policyEnumerator.MoveNext()
Dim currentLevel As PolicyLevel = CType(policyEnumerator.Current, PolicyLevel)
If currentLevel.Label = "Machine" Then
Dim copy As NamedPermissionSet = currentLevel.GetNamedPermissionSet(name)
Return CType(copy, PermissionSet)
End If
End While
Return Nothing
End Function 'GetNamedPermissionSet
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.
PermissionSet pset = GetNamedPermissionSet("LocalIntranet");
if (pset == null)
return;
// 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.exe", "C:\\sandbox\\HelloWorld.exe", true);
Evidence hostEvidence = new Evidence();
// Commenting out the following two statements 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.AddHost(new Zone(SecurityZone.Intranet));
hostEvidence.AddHost(new Url("C:\\Sandbox"));
// Create the sandboxed domain.
AppDomain sandbox = AppDomain.CreateDomain(
"Sandboxed Domain",
hostEvidence,
ads,
pset,
GetStrongName(Assembly.GetExecutingAssembly()));
sandbox.ExecuteAssemblyByName("HelloWorld");
}
/// <summary>
/// Get a strong name that matches the specified assembly.
/// </summary>
/// <exception cref="ArgumentNullException">
/// if <paramref name="assembly"/> is null
/// </exception>
/// <exception cref="InvalidOperationException">
/// if <paramref name="assembly"/> does not represent a strongly named assembly
/// </exception>
/// <param name="assembly">Assembly to create a StrongName for</param>
/// <returns>A StrongName for the given assembly</returns>
///
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);
}
private static PermissionSet GetNamedPermissionSet(string name)
{
IEnumerator policyEnumerator = SecurityManager.PolicyHierarchy();
// Move through the policy levels to the machine policy level.
while (policyEnumerator.MoveNext())
{
PolicyLevel currentLevel = (PolicyLevel)policyEnumerator.Current;
if (currentLevel.Label == "Machine")
{
NamedPermissionSet copy = currentLevel.GetNamedPermissionSet(name);
return (PermissionSet)copy;
}
}
return null;
}
}
}