方法: サンドボックスで部分信頼コードを実行するHow to: Run Partially Trusted Code in a Sandbox

注意事項

コード アクセス セキュリティと部分的に信頼できるコードCode Access Security and Partially Trusted Code

.NET Framework には、コード アクセス セキュリティ (CAS) と呼ばれる、同一アプリケーションで実行される各種コードにさまざまな信頼レベルを強制的に適用するメカニズムが備わっています。The .NET Framework provides a mechanism for the enforcement of varying levels of trust on different code running in the same application called Code Access Security (CAS). .NET Framework のコード アクセス セキュリティは、コードの実行元や他の ID 情報に基づいてセキュリティ境界を適用するメカニズムとして使用しないでください。Code Access Security in .NET Framework should not be used as a mechanism for enforcing security boundaries based on code origination or other identity aspects. 現在、部分的に信頼されるコード (特に実行元が不明なコード) では、コード アクセス セキュリティと透過的セキュリティ コードがセキュリティ境界としてサポートされないように、ガイダンスを更新しています。We are updating our guidance to reflect that Code Access Security and Security-Transparent Code will not be supported as a security boundary with partially trusted code, especially code of unknown origin. 発生元の不明なコードの読み込みと実行に関しては、他のセキュリティ対策を適切に導入することなく行わないようにしてください。We advise against loading and executing code of unknown origins without putting alternative security measures in place.

このポリシーは .NET Framework のすべてのバージョンに適用されますが、Silverlight に含まれる .NET Framework には適用されません。This policy applies to all versions of .NET Framework, but does not apply to the .NET Framework included in Silverlight.

サンドボックス化は、制限されたセキュリティ環境でコードを実行する方法です。この方法を採用すると、コードに付与されるアクセス許可が制限されます。Sandboxing is the practice of running code in a restricted security environment, which limits the access permissions granted to the code. たとえば、完全に信頼していない発行元のマネージド ライブラリは、完全信頼として実行しないようにする必要があります。For example, if you have a managed library from a source you do not completely trust, you should not run it as fully trusted. 代わりに、必要なアクセス許可 (Execution アクセス許可など) のみを与えるサンドボックスにコードを配置します。Instead, you should place the code in a sandbox that limits its permissions to those that you expect it to need (for example, Execution permission).

また、部分的に信頼された環境で実行する予定のコードについて、サンドボックスを使用してテストすることもできます。You can also use sandboxing to test code you will be distributing that will run in partially trusted environments.

AppDomain を使用すると、マネージド アプリケーションのサンドボックスを効果的に提供できます。An AppDomain is an effective way of providing a sandbox for managed applications. 部分信頼コードの実行時に使用するアプリケーション ドメインには、AppDomain 内で実行する際に利用できる保護対象リソースを定義するアクセス許可が与えられます。Application domains that are used for running partially trusted code have permissions that define the protected resources that are available when running within that AppDomain. AppDomain 内で実行されるコードは、AppDomain に関連付けられているアクセス許可によって制約され、指定したリソースにのみアクセスできます。Code that runs inside the AppDomain is bound by the permissions associated with the AppDomain and is allowed to access only the specified resources. また、AppDomain には、完全信頼として読み込むアセンブリを特定する StrongName 配列も含まれます。The AppDomain also includes a StrongName array that is used to identify assemblies that are to be loaded as fully trusted. これによって AppDomain の作成者は、新しいサンドボックス化されたドメインを開始して、特定のヘルパー アセンブリを完全信頼とすることができます。This enables the creator of an AppDomain to start a new sandboxed domain that allows specific helper assemblies to be fully trusted. アセンブリを完全信頼として読み込むには、グローバル アセンブリ キャッシュに配置する方法もあります。ただし、そのコンピューター上に作成されたすべてのアプリケーション ドメインに、アセンブリが完全信頼として読み込まれます。Another option for loading assemblies as fully trusted is to place them in the global assembly cache; however, that will load assemblies as fully trusted in all application domains created on that computer. 厳密な名前の一覧は AppDomain ごとに決定できるので、対象アセンブリのより限定的な指定が可能になります。The list of strong names supports a per-AppDomain decision that provides more restrictive determination.

サンドボックスで実行するアプリケーションのアクセス許可セットを指定するには、AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) メソッド オーバーロードを使用します。You can use the AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) method overload to specify the permission set for applications that run in a sandbox. このオーバーロードを使用することで、コード アクセス セキュリティのレベルを希望どおりに設定できます。This overload enables you to specify the exact level of code access security you want. このオーバーロードを使用して AppDomain に読み込まれるアセンブリには、指定の許可セットのみを付与することもできますし、完全信頼を付与することもできます。Assemblies that are loaded into an AppDomain by using this overload can either have the specified grant set only, or can be fully trusted. グローバル アセンブリ キャッシュ内のアセンブリ、または fullTrustAssemblies (StrongName) 配列パラメーターに列挙されているアセンブリには、完全信頼が付与されます。The assembly is granted full trust if it is in the global assembly cache or listed in the fullTrustAssemblies (the StrongName) array parameter. 完全に信頼できるアセンブリだけを fullTrustAssemblies リストに追加する必要があります。Only assemblies known to be fully trusted should be added to the fullTrustAssemblies list.

オーバーロードは次のシグネチャを持ちます。The overload has the following signature:

AppDomain.CreateDomain( string friendlyName,  
                        Evidence securityInfo,  
                        AppDomainSetup info,  
                        PermissionSet grantSet,  
                        params StrongName[] fullTrustAssemblies);  

CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) メソッド オーバーロードのパラメーターでは、AppDomain の名前、AppDomain の証拠、サンドボックスのアプリケーション ベースを指定する AppDomainSetup オブジェクト、使用するアクセス許可セット、および完全に信頼されたアセンブリの厳密な名前を指定します。The parameters for the CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) method overload specify the name of the AppDomain, the evidence for the AppDomain, the AppDomainSetup object that identifies the application base for the sandbox, the permission set to use, and the strong names for fully trusted assemblies.

セキュリティ上の理由から、info パラメーターに指定するアプリケーション ベースに、ホスト アプリケーションのアプリケーション ベースを指定することはできません。For security reasons, the application base specified in the info parameter should not be the application base for the hosting application.

grantSet パラメーターには、明示的に作成したアクセス許可セットを指定するか、GetStandardSandbox メソッドによって作成された標準アクセス許可セットを指定します。For the grantSet parameter, you can specify either a permission set you have explicitly created, or a standard permission set created by the GetStandardSandbox method.

他の多くの AppDomain 読み込みとは異なり、部分的に信頼されたアセンブリの許可セットの決定に (securityInfo パラメーターで指定される) AppDomain の証拠は使用されません。Unlike most AppDomain loads, the evidence for the AppDomain (which is provided by the securityInfo parameter) is not used to determine the grant set for the partially trusted assemblies. 代わりに、grantSet パラメーターによって単独で指定されます。Instead, it is independently specified by the grantSet parameter. ただし、分離ストレージのスコープの決定など、他の用途に証拠を使用できます。However, the evidence can be used for other purposes such as determining the isolated storage scope.

サンドボックスでアプリケーションを実行するにはTo run an application in a sandbox

  1. 信頼関係のないアプリケーションに付与するアクセス許可セットを作成します。Create the permission set to be granted to the untrusted application. 付与できる最小限のアクセス許可は Execution です。The minimum permission you can grant is Execution permission. また、信頼関係のないコードでも安全と考えられる追加のアクセス許可を付与することもできます。たとえば、IsolatedStorageFilePermission などです。You can also grant additional permissions you think might be safe for untrusted code; for example, IsolatedStorageFilePermission. 次のコードでは、Execution アクセス許可のみを含む新しいアクセス許可セットを作成します。The following code creates a new permission set with only Execution permission.

    PermissionSet permSet = new PermissionSet(PermissionState.None);  
    permSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));  
    

    また、"Internet" など、既存の名前付きアクセス許可セットを使用することもできます。Alternatively, you can use an existing named permission set, such as Internet.

    Evidence ev = new Evidence();  
    ev.AddHostEvidence(new Zone(SecurityZone.Internet));  
    PermissionSet internetPS = SecurityManager.GetStandardSandbox(ev);  
    

    証拠のゾーンに応じて、GetStandardSandbox メソッドは Internet アクセス許可セットまたは LocalIntranet アクセス許可セットを返します。The GetStandardSandbox method returns either an Internet permission set or a LocalIntranet permission set depending on the zone in the evidence. また、GetStandardSandbox は、参照として渡される一部の証拠オブジェクトの ID アクセス許可を構築します。GetStandardSandbox also constructs identity permissions for some of the evidence objects passed as references.

  2. 信頼関係のないコードを呼び出すホスト クラス (この例では Sandboxer) を含むアセンブリに署名します。Sign the assembly that contains the hosting class (named Sandboxer in this example) that calls the untrusted code. アセンブリの署名で使用した StrongName を、StrongName を呼び出す際の fullTrustAssemblies パラメーターに CreateDomain 配列として追加します。Add the StrongName used to sign the assembly to the StrongName array of the fullTrustAssemblies parameter of the CreateDomain call. 部分信頼コードを実行できるようにする場合、または部分信頼アプリケーションにサービスを提供する場合は、ホスト クラスを完全信頼として実行する必要があります。The hosting class must run as fully trusted to enable the execution of the partial-trust code or to offer services to the partial-trust application. アセンブリの StrongName を読み取る方法は次のとおりです。This is how you read the StrongName of an assembly:

    StrongName fullTrustAssembly = typeof(Sandboxer).Assembly.Evidence.GetHostEvidence<StrongName>();  
    

    mscorlib や System.dll などの .NET Framework アセンブリを完全信頼一覧に追加することはできません。グローバル アセンブリ キャッシュから完全信頼として読み込まれているためです。.NET Framework assemblies such as mscorlib and System.dll do not have to be added to the full-trust list because they are loaded as fully trusted from the global assembly cache.

  3. CreateDomain メソッドの AppDomainSetup パラメーターを初期化します。Initialize the AppDomainSetup parameter of the CreateDomain method. このパラメーターを使用すると、新しい AppDomain の多くの設定を制御できます。With this parameter, you can control many of the settings of the new AppDomain. ApplicationBase プロパティは重要な設定なので、ホスト アプリケーションの AppDomainApplicationBase プロパティとは違う設定にする必要があります。The ApplicationBase property is an important setting, and should be different from the ApplicationBase property for the AppDomain of the hosting application. ApplicationBase 設定が同じ場合、部分的に信頼されたアプリケーションは、ホスト アプリケーションが定義する例外を完全信頼として読み込み、それを悪用できるようになります。If the ApplicationBase settings are the same, the partial-trust application can get the hosting application to load (as fully trusted) an exception it defines, thus exploiting it. これは、キャッシュ (例外) が推奨されないもう 1 つの理由です。This is another reason why a catch (exception) is not recommended. ホストのアプリケーション ベースと、サンドボックス アプリケーションのアプリケーション ベースを異なる設定にすると、悪用のリスクが軽減されます。Setting the application base of the host differently from the application base of the sandboxed application mitigates the risk of exploits.

    AppDomainSetup adSetup = new AppDomainSetup();  
    adSetup.ApplicationBase = Path.GetFullPath(pathToUntrusted);  
    
  4. CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) メソッド オーバーロードを呼び出し、指定したパラメーターを使用してアプリケーション ドメインを作成します。Call the CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) method overload to create the application domain using the parameters we have specified.

    このメソッドのシグネチャは次のとおりです。The signature for this method is:

    public static AppDomain CreateDomain(string friendlyName,   
        Evidence securityInfo, AppDomainSetup info, PermissionSet grantSet,   
        params StrongName[] fullTrustAssemblies)  
    

    追加情報:Additional information:

    • これは、パラメーターとして PermissionSet を使用する CreateDomain メソッドの唯一のオーバーロードです。つまり、部分信頼設定でアプリケーションを読み込むことができる唯一のオーバーロードになります。This is the only overload of the CreateDomain method that takes a PermissionSet as a parameter, and thus the only overload that lets you load an application in a partial-trust setting.

    • evidence パラメーターは、アクセス許可セットの計算では使用されません。このパラメーターは、.NET Framework の他の機能が識別目的で使用します。The evidence parameter is not used to calculate a permission set; it is used for identification by other features of the .NET Framework.

    • このオーバーロードでは、info パラメーターの ApplicationBase プロパティを必ず設定します。Setting the ApplicationBase property of the info parameter is mandatory for this overload.

    • fullTrustAssemblies パラメーターには params キーワードがあります。これは StrongName 配列を作成する必要がないことを示します。The fullTrustAssemblies parameter has the params keyword, which means that it is not necessary to create a StrongName array. パラメーターとして、0 個、1 個、または複数の厳密な名前を渡すことができます。Passing 0, 1, or more strong names as parameters is allowed.

    • アプリケーション ドメインを作成するコードは次のとおりです。The code to create the application domain is:

    AppDomain newDomain = AppDomain.CreateDomain("Sandbox", null, adSetup, permSet, fullTrustAssembly);  
    
  5. 作成したサンドボックスの AppDomain にコードを読み込みます。Load the code into the sandboxing AppDomain that you created. これは、次の 2 つの方法で行うことができます。This can be done in two ways:

    2 番目の方が望ましい方法です。新しい AppDomain インスタンスにパラメーターを渡しやすいためです。The second method is preferable, because it makes it easier to pass parameters to the new AppDomain instance. CreateInstanceFrom メソッドには 2 つの重要な機能があります。The CreateInstanceFrom method provides two important features:

    • アセンブリが保存されていない場所を示すコード ベースを使用できます。You can use a code base that points to a location that does not contain your assembly.

    • Assert の下で、完全信頼 (PermissionState.Unrestricted) で作成操作を実行できます。こうすることで、重要なクラスのインスタンスを作成できます。You can do the creation under an Assert for full-trust (PermissionState.Unrestricted), which enables you to create an instance of a critical class. (この状況は、アセンブリに透過マーキングがなく、完全信頼として読み込まれるときに毎回発生します)。そのため、この関数で信頼するコードのみを作成する場合は注意が必要です。新しいアプリケーション ドメインに、完全信頼クラスのインスタンスのみを作成することをお勧めします。(This happens whenever your assembly has no transparency markings and is loaded as fully trusted.) Therefore, you have to be careful to create only code that you trust with this function, and we recommend that you create only instances of fully trusted classes in the new application domain.

    ObjectHandle handle = Activator.CreateInstanceFrom(  
    newDomain, typeof(Sandboxer).Assembly.ManifestModule.FullyQualifiedName,  
           typeof(Sandboxer).FullName );  
    

    新しいドメインにクラスのインスタンスを作成するには、そのクラスで MarshalByRefObject クラスを拡張する必要があります。Note that in order to create an instance of a class in a new domain, the class has to extend the MarshalByRefObject class

    class Sandboxer:MarshalByRefObject  
    
  6. 新しいドメイン インスタンスをこのドメイン内の参照にラップ解除します。Unwrap the new domain instance into a reference in this domain. この参照は、信頼関係のないコードを実行するときに使用されます。This reference is used to execute the untrusted code.

    Sandboxer newDomainInstance = (Sandboxer) handle.Unwrap();  
    
  7. 作成した Sandboxer クラスのインスタンスで、ExecuteUntrustedCode メソッドを呼び出します。Call the ExecuteUntrustedCode method in the instance of the Sandboxer class you just created.

    newDomainInstance.ExecuteUntrustedCode(untrustedAssembly, untrustedClass, entryPoint, parameters);  
    

    この呼び出しは、アクセス許可が制限されているサンドボックス アプリケーション ドメインで実行されます。This call is executed in the sandboxed application domain, which has restricted permissions.

    public void ExecuteUntrustedCode(string assemblyName, string typeName, string entryPoint, Object[] parameters)  
    {  
        //Load the MethodInfo for a method in the new assembly. This might be a method you know, or   
        //you can use Assembly.EntryPoint to get to the entry point in an executable.  
        MethodInfo target = Assembly.Load(assemblyName).GetType(typeName).GetMethod(entryPoint);  
        try  
        {  
            // Invoke the method.  
            target.Invoke(null, parameters);  
        }  
        catch (Exception ex)  
        {  
        //When information is obtained from a SecurityException extra information is provided if it is   
        //accessed in full-trust.  
            new PermissionSet(PermissionState.Unrestricted).Assert();  
            Console.WriteLine("SecurityException caught:\n{0}", ex.ToString());  
            CodeAccessPermission.RevertAssert();  
            Console.ReadLine();  
        }  
    }  
    

    System.Reflection を使用して、部分的に信頼されたアセンブリでメソッドのハンドルを取得します。System.Reflection is used to get a handle of a method in the partially trusted assembly. このハンドルは、最小限のアクセス許可を持つ安全な方法でコードを実行するために使用できます。The handle can be used to execute code in a safe way with minimum permissions.

    上記のコードでは、SecurityException を出力する前に完全信頼のアクセス許可の Assert があることがわかります。In the previous code, note the Assert for the full-trust permission before printing the SecurityException.

    new PermissionSet(PermissionState.Unrestricted).Assert()  
    

    完全信頼アサートは、SecurityException から拡張情報を取得するために使用します。The full-trust assert is used to obtain extended information from the SecurityException. Assert を使用しない場合、SecurityExceptionToString メソッドは、スタック上に部分的に信頼されたコードがあることを検出します。また、返される情報を制限します。Without the Assert, the ToString method of SecurityException will discover that there is partially trusted code on the stack and will restrict the information returned. 部分信頼コードがその情報を読み取ることができる場合、これによってセキュリティ上の問題が発生する可能性もありますが、UIPermission を付与しないことでそのリスクは軽減されます。This could cause security issues if the partial-trust code could read that information, but the risk is mitigated by not granting UIPermission. 完全信頼アサートは慎重に使用する必要があります。部分信頼コードが完全信頼に昇格できないことが確実である場合にのみ使用します。The full-trust assert should be used sparingly and only when you are sure that you are not allowing partial-trust code to elevate to full trust. 通則として、信頼できないコードは、完全信頼のアサートを呼び出した後に同じ関数で呼び出すのは避ける必要があります。As a rule, do not call code you do not trust in the same function and after you called an assert for full trust. アサートの使用を完了したときは、常にアサートを元に戻すことをお勧めします。It is good practice to always revert the assert when you have finished using it.

Example

次の例では、前のセクションの手順を実装しています。The following example implements the procedure in the previous section. この例では、Visual Studio ソリューションの Sandboxer というプロジェクトにも UntrustedCode というプロジェクトが含まれます。これはクラス UntrustedClass を実装します。In the example, a project named Sandboxer in a Visual Studio solution also contains a project named UntrustedCode, which implements the class UntrustedClass. このシナリオでは、指定した数字がフィボナッチ数かどうかを示すために、true または false を返すことが期待されているメソッドを含むライブラリ アセンブリをダウンロードしたことを想定しています。This scenario assumes that you have downloaded a library assembly containing a method that is expected to return true or false to indicate whether the number you provided is a Fibonacci number. 代わりに、このメソッドはコンピューターからのファイルの読み込みを試みます。Instead, the method attempts to read a file from your computer. 次の例は信頼関係のないコードを示します。The following example shows the untrusted code.

using System;  
using System.IO;  
namespace UntrustedCode  
{  
    public class UntrustedClass  
    {  
        // Pretend to be a method checking if a number is a Fibonacci  
        // but which actually attempts to read a file.  
        public static bool IsFibonacci(int number)  
        {  
           File.ReadAllText("C:\\Temp\\file.txt");  
           return false;  
        }  
    }  
}  

次の例は、信頼関係のないコードを実行する Sandboxer アプリケーション コードを示します。The following example shows the Sandboxer application code that executes the untrusted code.

using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Text;  
using System.IO;  
using System.Security;  
using System.Security.Policy;  
using System.Security.Permissions;  
using System.Reflection;  
using System.Runtime.Remoting;  
  
//The Sandboxer class needs to derive from MarshalByRefObject so that we can create it in another   
// AppDomain and refer to it from the default AppDomain.  
class Sandboxer : MarshalByRefObject  
{  
    const string pathToUntrusted = @"..\..\..\UntrustedCode\bin\Debug";  
    const string untrustedAssembly = "UntrustedCode";  
    const string untrustedClass = "UntrustedCode.UntrustedClass";  
    const string entryPoint = "IsFibonacci";  
    private static Object[] parameters = { 45 };  
    static void Main()  
    {  
        //Setting the AppDomainSetup. It is very important to set the ApplicationBase to a folder   
        //other than the one in which the sandboxer resides.  
        AppDomainSetup adSetup = new AppDomainSetup();  
        adSetup.ApplicationBase = Path.GetFullPath(pathToUntrusted);  
  
        //Setting the permissions for the AppDomain. We give the permission to execute and to   
        //read/discover the location where the untrusted code is loaded.  
        PermissionSet permSet = new PermissionSet(PermissionState.None);  
        permSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));  
  
        //We want the sandboxer assembly's strong name, so that we can add it to the full trust list.  
        StrongName fullTrustAssembly = typeof(Sandboxer).Assembly.Evidence.GetHostEvidence<StrongName>();  
  
        //Now we have everything we need to create the AppDomain, so let's create it.  
        AppDomain newDomain = AppDomain.CreateDomain("Sandbox", null, adSetup, permSet, fullTrustAssembly);  
  
        //Use CreateInstanceFrom to load an instance of the Sandboxer class into the  
        //new AppDomain.   
        ObjectHandle handle = Activator.CreateInstanceFrom(  
            newDomain, typeof(Sandboxer).Assembly.ManifestModule.FullyQualifiedName,  
            typeof(Sandboxer).FullName  
            );  
        //Unwrap the new domain instance into a reference in this domain and use it to execute the   
        //untrusted code.  
        Sandboxer newDomainInstance = (Sandboxer) handle.Unwrap();  
        newDomainInstance.ExecuteUntrustedCode(untrustedAssembly, untrustedClass, entryPoint, parameters);  
    }  
    public void ExecuteUntrustedCode(string assemblyName, string typeName, string entryPoint, Object[] parameters)  
    {  
        //Load the MethodInfo for a method in the new Assembly. This might be a method you know, or   
        //you can use Assembly.EntryPoint to get to the main function in an executable.  
        MethodInfo target = Assembly.Load(assemblyName).GetType(typeName).GetMethod(entryPoint);  
        try  
        {  
            //Now invoke the method.  
            bool retVal = (bool)target.Invoke(null, parameters);  
        }  
        catch (Exception ex)  
        {  
            // When we print informations from a SecurityException extra information can be printed if we are   
            //calling it with a full-trust stack.  
            new PermissionSet(PermissionState.Unrestricted).Assert();  
            Console.WriteLine("SecurityException caught:\n{0}", ex.ToString());  
            CodeAccessPermission.RevertAssert();  
            Console.ReadLine();  
        }  
    }  
}  

関連項目See also