Procedura: eseguire codice parzialmente attendibile in un oggetto sandboxHow to: Run Partially Trusted Code in a Sandbox

Attenzione

Sicurezza dall'accesso di codice e codice parzialmente attendibileCode Access Security and Partially Trusted Code

.NET Framework fornisce un meccanismo denominato sicurezza dall'accesso di codice, che consente di applicare vari livelli di attendibilità a codice diverso in esecuzione nella stessa applicazione.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). La sicurezza per l'accesso di codice in .NET Framework non deve essere usata come meccanismo per l'applicazione dei limiti di sicurezza in base alla creazione di codice o altri aspetti di identità.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. Le linee guida sono state modificate per specificare che la sicurezza per l'accesso di codice e il codice SecurityTransparent non saranno supportati come limiti di sicurezza con codice parzialmente attendibile, soprattutto nel caso di codice di origine sconosciuta.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. Non è consigliabile caricare ed eseguire codice di origine sconosciuta in assenza di misure di sicurezza alternative.We advise against loading and executing code of unknown origins without putting alternative security measures in place.

Questi criteri si applicano a tutte le versioni di .NET Framework, ma non alla versione di .NET Framework inclusa in Silverlight.This policy applies to all versions of .NET Framework, but does not apply to the .NET Framework included in Silverlight.

Il termine sandboxing si riferisce all'esecuzione di codice in un ambiente di sicurezza con restrizioni che limita le autorizzazioni di accesso concesse al codice.Sandboxing is the practice of running code in a restricted security environment, which limits the access permissions granted to the code. Se, ad esempio, si dispone di una libreria gestita proveniente da un'origine non considerata completamente attendibile, è consigliabile non eseguirla come completamente attendibile.For example, if you have a managed library from a source you do not completely trust, you should not run it as fully trusted. Inserire invece il codice in un ambiente sandbox che limita le autorizzazioni a quelle che si prevede siano necessarie (ad esempio, l'autorizzazione 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).

È anche possibile usare il sandboxing per testare il codice da distribuire che verrà eseguito in ambienti parzialmente attendibili.You can also use sandboxing to test code you will be distributing that will run in partially trusted environments.

Un oggetto AppDomain costituisce un modo efficace per fornire un ambiente sandbox per le applicazioni gestite.An AppDomain is an effective way of providing a sandbox for managed applications. I domini applicazione usati per l'esecuzione di codice parzialmente attendibile dispongono di autorizzazioni che definiscono le risorse protette disponibili durante l'esecuzione in 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. Il codice eseguito in AppDomain è vincolato dalle autorizzazioni associate a AppDomain e può accedere solo alle risorse specificate.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 include anche una matrice StrongName usata per identificare gli assembly da caricare come completamente attendibili.The AppDomain also includes a StrongName array that is used to identify assemblies that are to be loaded as fully trusted. In questo modo, il creatore di un oggetto AppDomain può avviare un nuovo dominio in modalità sandbox tramite cui gli assembly helper vengono considerati completamente attendibili.This enables the creator of an AppDomain to start a new sandboxed domain that allows specific helper assemblies to be fully trusted. Un'altra opzione per il caricamento degli assembly come completamente attendibili consiste nel collocarli nella Global Assembly Cache. In questo modo, tuttavia, gli assembly verranno caricati come completamente attendibili in tutti i domini applicazione creati in tale computer.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. L'elenco di nomi sicuri consente di prendere una decisione per ogni oggetto AppDomain, offrendo quindi caratteristiche più restrittive.The list of strong names supports a per-AppDomain decision that provides more restrictive determination.

È possibile usare l'overload del metodo AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) per specificare il set di autorizzazioni per le applicazioni eseguite in un ambiente sandbox.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. Questo overload consente di specificare il livello esatto di sicurezza dall'accesso di codice desiderato.This overload enables you to specify the exact level of code access security you want. Gli assembly caricati in un oggetto AppDomain usando questo overload possono solo disporre del set di autorizzazioni specificato o essere considerati completamente attendibili.Assemblies that are loaded into an AppDomain by using this overload can either have the specified grant set only, or can be fully trusted. L'assembly viene considerato completamente attendibile se è presente nella Global Assembly Cache o elencato nel parametro della matrice 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. Solo gli assembly completamente attendibili devono essere aggiunti all'elenco fullTrustAssemblies.Only assemblies known to be fully trusted should be added to the fullTrustAssemblies list.

L'overload ha la firma seguente:The overload has the following signature:

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

I parametri per l'overload del metodo CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) specificano il nome di AppDomain, l'evidenza per AppDomain, l'oggetto AppDomainSetup che identifica la base dell'applicazione per l'ambiente sandbox, il set di autorizzazioni da usare e i nomi sicuri per gli assembly completamente attendibili.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.

Per motivi di sicurezza, la base dell'applicazione specificata nel parametro info non deve corrispondere alla base dell'applicazione host.For security reasons, the application base specified in the info parameter should not be the application base for the hosting application.

Per il parametro grantSet, è possibile specificare un set di autorizzazioni creato in modo esplicito o un set di autorizzazioni standard creato dal metodo 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.

A differenza della maggior parte dei caricamenti di AppDomain, l'evidenza per AppDomain (fornita dal parametro securityInfo) non viene usata per determinare il set di autorizzazioni per gli assembly parzialmente attendibili.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. Viene invece specificata in modo indipendente dal parametro grantSet.Instead, it is independently specified by the grantSet parameter. L'evidenza può essere usata per altri scopi, ad esempio per determinare l'ambito dello spazio di memorizzazione isolato.However, the evidence can be used for other purposes such as determining the isolated storage scope.

Per eseguire un'applicazione in un ambiente sandboxTo run an application in a sandbox

  1. Creare il set di autorizzazioni da concedere all'applicazione non attendibile.Create the permission set to be granted to the untrusted application. L'autorizzazione minima che è possibile concedere è Execution.The minimum permission you can grant is Execution permission. È anche possibile concedere autorizzazioni aggiuntive che si ritengono sicure per il codice non attendibile, ad esempio IsolatedStorageFilePermission.You can also grant additional permissions you think might be safe for untrusted code; for example, IsolatedStorageFilePermission. Il codice seguente crea un nuovo set di autorizzazioni con solo l'autorizzazione 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));  
    

    In alternativa, è possibile usare un set di autorizzazioni denominato esistente, ad esempio 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);  
    

    Il metodo GetStandardSandbox restituisce un set di autorizzazioni Internet o un set di autorizzazioni LocalIntranet, a seconda dell'area nell'evidenza.The GetStandardSandbox method returns either an Internet permission set or a LocalIntranet permission set depending on the zone in the evidence. GetStandardSandbox crea inoltre autorizzazioni di identità per alcuni degli oggetti evidenza passati come riferimenti.GetStandardSandbox also constructs identity permissions for some of the evidence objects passed as references.

  2. Firmare l'assembly contenente la classe host (in questo esempio Sandboxer) che chiama il codice non attendibile.Sign the assembly that contains the hosting class (named Sandboxer in this example) that calls the untrusted code. Aggiungere l'oggetto StrongName usato per firmare l'assembly alla matrice StrongName del parametro fullTrustAssemblies della chiamata a CreateDomain.Add the StrongName used to sign the assembly to the StrongName array of the fullTrustAssemblies parameter of the CreateDomain call. La classe host deve essere eseguita come completamente attendibile per consentire l'esecuzione del codice parzialmente attendibile o per offrire servizi per l'applicazione parzialmente attendibile.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. Ecco come viene letto l'oggetto StrongName di un assembly:This is how you read the StrongName of an assembly:

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

    Non è necessario aggiungere gli assembly .NET Framework, come mscorlib e System. dll, all'elenco di elementi completamente attendibili, in quanto vengono caricati come completamente attendibili dalla Global Assembly Cache..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. Inizializzare il parametro AppDomainSetup del metodo CreateDomain.Initialize the AppDomainSetup parameter of the CreateDomain method. Con questo parametro, è possibile controllare numerose impostazioni del nuovo oggetto AppDomain.With this parameter, you can control many of the settings of the new AppDomain. La proprietà ApplicationBase è un'impostazione importante e deve essere diversa dalla proprietà ApplicationBase per l'oggetto AppDomain dell'applicazione host.The ApplicationBase property is an important setting, and should be different from the ApplicationBase property for the AppDomain of the hosting application. Se le impostazioni di ApplicationBase corrispondono, l'applicazione parzialmente attendibile può fare in modo che l'applicazione host carichi (come completamente attendibile) un'eccezione definita, che può quindi essere sfruttata.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. Questo è un altro motivo per cui non è consigliabile l'uso di un elemento catch (eccezione).This is another reason why a catch (exception) is not recommended. Impostando la base dell'applicazione dell'host in modo diverso dalla base dell'applicazione in modalità sandbox, è possibile ridurre il rischio di exploit.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. Chiamare l'overload del metodo CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) per creare il dominio dell'applicazione usando i parametri specificati.Call the CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) method overload to create the application domain using the parameters we have specified.

    La firma per il metodo è la seguente:The signature for this method is:

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

    Informazioni aggiuntive:Additional information:

    • Questo è l'unico overload del metodo CreateDomain che accetta un oggetto PermissionSet come parametro e pertanto l'unico overload che consente di caricare un'applicazione con un'impostazione di attendibilità parziale.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.

    • Il parametro evidence non viene usato per calcolare un set di autorizzazioni, ma per l'identificazione da parte di altre funzionalità di .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.

    • L'impostazione della proprietà ApplicationBase del parametro info è obbligatoria per questo overload.Setting the ApplicationBase property of the info parameter is mandatory for this overload.

    • Il parametro fullTrustAssemblies dispone della parola chiave params, pertanto non è necessario creare una matrice StrongName.The fullTrustAssemblies parameter has the params keyword, which means that it is not necessary to create a StrongName array. È possibile passare 0, 1 o più nomi sicuri come parametri.Passing 0, 1, or more strong names as parameters is allowed.

    • Il codice per creare il dominio applicazione è il seguente:The code to create the application domain is:

    AppDomain newDomain = AppDomain.CreateDomain("Sandbox", null, adSetup, permSet, fullTrustAssembly);  
    
  5. Caricare il codice nell'oggetto AppDomain sandbox creato.Load the code into the sandboxing AppDomain that you created. Questa operazione può essere eseguita nei due modi seguenti.This can be done in two ways:

    Il secondo metodo è preferibile, in quanto consente di passare in modo più semplice i parametri alla nuova istanza di AppDomain.The second method is preferable, because it makes it easier to pass parameters to the new AppDomain instance. Il metodo CreateInstanceFrom offre due funzionalità importanti:The CreateInstanceFrom method provides two important features:

    • È possibile usare una codebase che punta a una posizione che non contiene l'assembly.You can use a code base that points to a location that does not contain your assembly.

    • È possibile eseguire la creazione in un oggetto Assert per l'attendibilità totale (PermissionState.Unrestricted), per poter creare un'istanza di una classe critica.You can do the creation under an Assert for full-trust (PermissionState.Unrestricted), which enables you to create an instance of a critical class. Ciò avviene ogni volta che l'assembly non dispone di contrassegni di trasparenza e viene caricato come completamente attendibile. È pertanto necessario prestare attenzione a creare solo codice attendibile con questa funzione e si consiglia di creare solo istanze di classi completamente attendibili nel nuovo dominio applicazione.(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 );  
    

    Si noti che per creare un'istanza di una classe in un nuovo dominio, la classe deve estendere la classe 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. Annullare il wrapping dell'istanza del nuovo dominio in un riferimento in questo dominio.Unwrap the new domain instance into a reference in this domain. Questo riferimento viene usato per eseguire codice non attendibile.This reference is used to execute the untrusted code.

    Sandboxer newDomainInstance = (Sandboxer) handle.Unwrap();  
    
  7. Chiamare il metodo ExecuteUntrustedCode nell'istanza della classe Sandboxer appena creata.Call the ExecuteUntrustedCode method in the instance of the Sandboxer class you just created.

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

    Questa chiamata viene eseguita nel dominio applicazione in modalità sandbox, con autorizzazioni limitate.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();  
            }  
        }  
    

    Viene usato System.Reflection per ottenere un handle di un metodo nell'assembly parzialmente attendibile.System.Reflection is used to get a handle of a method in the partially trusted assembly. L'handle può essere usato per eseguire codice in modo sicuro con autorizzazioni minime.The handle can be used to execute code in a safe way with minimum permissions.

    Nel codice precedente, osservare l'oggetto Assert per l'autorizzazione di attendibilità totale prima di stampare SecurityException.In the previous code, note the Assert for the full-trust permission before printing the SecurityException.

    new PermissionSet(PermissionState.Unrestricted)).Assert()  
    

    L'asserzione di attendibilità totale viene usata per ottenere informazioni estese da SecurityException.The full-trust assert is used to obtain extended information from the SecurityException. Senza l'oggetto Assert, il metodo ToString di SecurityException individuerebbe la presenza di codice parzialmente attendibile nello stack e limiterebbe le informazioni restituite.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. Ciò potrebbe causare problemi di sicurezza se il codice parzialmente attendibile potesse leggere tali informazioni, ma i rischi vengono attenuati non concedendo UIPermission.This could cause security issues if the partial-trust code could read that information, but the risk is mitigated by not granting UIPermission. L'asserzione di attendibilità totale deve essere usata con cautela e solo quando si è certi di non consentire l'elevazione di codice parzialmente attendibile a codice completamente attendibile.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. Di norma, non chiamare codice non considerato attendibile nella stessa funzione e dopo avere chiamato un'asserzione di attendibilità totale.As a rule, do not call code you do not trust in the same function and after you called an assert for full trust. È consigliabile annullare sempre l'asserzione dopo averla usata.It is good practice to always revert the assert when you have finished using it.

EsempioExample

Nell'esempio seguente viene implementata la procedura della sezione precedente.The following example implements the procedure in the previous section. Nell'esempio un progetto denominato Sandboxer in una soluzione di Visual Studio contiene un progetto denominato UntrustedCode, che implementa la classe UntrustedClass.In the example, a project named Sandboxer in a Visual Studio solution also contains a project named UntrustedCode, which implements the class UntrustedClass. Questo scenario presuppone che sia stato scaricato un assembly di librerie contenente un metodo che restituisce true o false per indicare se il numero fornito è un numero di Fibonacci.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. Il metodo tenta invece di leggere un file dal computer.Instead, the method attempts to read a file from your computer. L'esempio seguente mostra il codice non attendibile.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;  
        }  
    }  
}  

L'esempio seguente mostra il codice dell'applicazione Sandboxer che esegue il codice non attendibile.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();  
        }  
    }  
}  

Vedere ancheSee Also

Linee guida per la generazione di codice sicuroSecure Coding Guidelines