Comment : exécuter du code d'un niveau de confiance partiel dans un bac à sable (sandbox)How to: Run Partially Trusted Code in a Sandbox

Attention

Sécurité d’accès du code (CAS) et code de confiance partielleCode Access Security (CAS) and Partially Trusted Code

Le .NET Framework fournit un mécanisme, appelé « sécurité d'accès du code (CAS) », qui permet de mettre en œuvre différents niveaux de confiance sur différents codes exécutés dans la même application.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).

Les autorités de certification ne sont pas prises en charge dans .NET Core, .NET 5 ou versions ultérieures. Les autorités de certification ne sont pas prises en charge par les versions de C# ultérieures à 7,0.CAS is not supported in .NET Core, .NET 5, or later versions. CAS is not supported by versions of C# later than 7.0.

Dans .NET Framework, les autorités de certification ne doivent pas être utilisées comme mécanisme pour appliquer des limites de sécurité basées sur l’origine du code ou d’autres aspects de l’identité.CAS in .NET Framework should not be used as a mechanism for enforcing security boundaries based on code origination or other identity aspects. Le code CAS et Security-Transparent ne sont pas pris en charge comme limite de sécurité avec du code d’un niveau de confiance partiel, en particulier le code d’origine inconnue.CAS and Security-Transparent Code are not supported as a security boundary with partially trusted code, especially code of unknown origin. Nous vous déconseillons de charger et d'exécuter du code d'origine inconnue sans mettre en place d'autres mesures de sécurité.We advise against loading and executing code of unknown origins without putting alternative security measures in place. .NET Framework n’émet pas de correctifs de sécurité pour les attaques d’élévation de privilège qui peuvent être découvertes sur le bac à sable (sandbox)..NET Framework will not issue security patches for any elevation-of-privilege exploits that might be discovered against the CAS sandbox.

Cette stratégie s'applique à toutes les versions du .NET Framework, mais ne concerne pas le .NET Framework inclus dans Silverlight.This policy applies to all versions of .NET Framework, but does not apply to the .NET Framework included in Silverlight.

L'utilisation de bac à sable (sandbox) consiste à exécuter du code dans un environnement de sécurité restreint qui limite les autorisations d'accès accordées au code.Sandboxing is the practice of running code in a restricted security environment, which limits the access permissions granted to the code. Par exemple, si une bibliothèque managée provient d'une source qui n'est pas totalement fiable, vous ne devez pas l'exécuter comme ayant un niveau de confiance totale.For example, if you have a managed library from a source you do not completely trust, you should not run it as fully trusted. Au lieu de cela, placez le code dans un bac à sable (sandbox) qui limite ses autorisations à ceux qui en ont besoin (par exemple, l'autorisation 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).

Vous pouvez également utiliser un bac à sable (sandbox) pour tester le code pour tester du code à distribuer qui s'exécute dans des environnements partiellement fiables.You can also use sandboxing to test code you will be distributing that will run in partially trusted environments.

Un AppDomain est un moyen efficace de fournir un bac à sable (sandbox) pour les applications managées.An AppDomain is an effective way of providing a sandbox for managed applications. Les domaines d'application utilisés pour l'exécution du code de niveau de confiance partiel disposent d'autorisations qui définissent les ressources protégées disponibles au moment de l'exécution dans ce 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. Le code qui s'exécute à l'intérieur du AppDomain est lié au AppDomain par les autorisations qui lui sont associées et est autorisé à accéder uniquement aux ressources spécifiées.Code that runs inside the AppDomain is bound by the permissions associated with the AppDomain and is allowed to access only the specified resources. Le AppDomain inclut également un tableau StrongName utilisé pour identifier les assemblys qui seront chargés avec un niveau de confiance totale.The AppDomain also includes a StrongName array that is used to identify assemblies that are to be loaded as fully trusted. Cela permet au concepteur d'un AppDomain de démarrer un nouveau domaine bac à sable (sandbox) qui permet aux assemblys d'assistance spécifiques d'avoir un niveau de confiance totale.This enables the creator of an AppDomain to start a new sandboxed domain that allows specific helper assemblies to be fully trusted. Une autre option pour le chargement d'assemblys avec un niveau de confiance totale est de les placer dans le Global Assembly Cache ; toutefois, cela les charge avec un niveau de confiance totale dans tous les domaines d'application créés sur l'ordinateur.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. La liste des noms forts prend en charge une décision pour chaque AppDomain qui fournit une détermination plus restrictive.The list of strong names supports a per-AppDomain decision that provides more restrictive determination.

Vous pouvez utiliser la surcharge de la méthode AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) pour définir le jeu d'autorisations des applications qui s'exécutent dans un bac à sable (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. Cette surcharge vous permet de spécifier le niveau de sécurité d'accès du code exact que vous souhaitez.This overload enables you to specify the exact level of code access security you want. Les assemblys chargés dans un AppDomain à l'aide de cette surcharge peuvent disposer soit uniquement du jeu d'autorisations spécifié, soit de la confiance totale.Assemblies that are loaded into an AppDomain by using this overload can either have the specified grant set only, or can be fully trusted. La confiance totale est accordée à l'assembly s'il se trouve dans le Global Assembly Cache ou est répertorié dans le paramètre de tableau 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. Seuls les assemblys réputés être entièrement fiables doivent être ajoutés à la liste fullTrustAssemblies.Only assemblies known to be fully trusted should be added to the fullTrustAssemblies list.

La surcharge possède la signature suivante :The overload has the following signature:

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

Les paramètres de la surcharge de méthode CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) spécifient le nom du AppDomain, la preuve du AppDomain, l'objet AppDomainSetup qui identifie la base de l'application pour le bac à sable (sandbox), le jeu d'autorisations à utiliser et les noms forts des assemblys entièrement fiables.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.

Pour des raisons de sécurité, la base de l'application définie dans le paramètre info ne doit pas être la base de l'application pour l'application d'hébergement.For security reasons, the application base specified in the info parameter should not be the application base for the hosting application.

Pour le paramètre grantSet, vous pouvez spécifier un jeu d'autorisations que vous avez explicitement créé ou un jeu d'autorisations standard créé par la méthode 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.

Contrairement à la plupart des surcharges AppDomain, la preuve pour le AppDomain (fournie par le paramètre securityInfo) n'est pas utilisée pour déterminer le jeu d'autorisations pour les assemblys partiellement fiables.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. Elle est en fait spécifiée indépendamment par le paramètre grantSet.Instead, it is independently specified by the grantSet parameter. Toutefois, la preuve peut être utilisée à d'autres fins, par exemple, pour déterminer la portée de stockage isolé.However, the evidence can be used for other purposes such as determining the isolated storage scope.

Pour exécuter une application dans un bac à sable (sandbox)To run an application in a sandbox

  1. Créez le jeu d'autorisations à accorder à l'application non fiable.Create the permission set to be granted to the untrusted application. L'autorisation minimale que vous pouvez accorder est l'autorisation Execution.The minimum permission you can grant is Execution permission. Vous pouvez également accorder des autorisations supplémentaires que vous pensez sécurisées pour du code non fiable ; par exemple, IsolatedStorageFilePermission.You can also grant additional permissions you think might be safe for untrusted code; for example, IsolatedStorageFilePermission. Le code suivant crée un jeu d'autorisations uniquement avec l'autorisation 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));  
    

    Vous pouvez également utiliser un jeu d'autorisations nommé existant, tel qu'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);  
    

    En fonction de la zone dans la preuve, la méthode GetStandardSandbox retourne un jeu d'autorisations Internet ou un jeu d'autorisations LocalIntranet.The GetStandardSandbox method returns either an Internet permission set or a LocalIntranet permission set depending on the zone in the evidence. GetStandardSandbox construit également des autorisations d'identité pour certains objets de preuve passés comme références.GetStandardSandbox also constructs identity permissions for some of the evidence objects passed as references.

  2. Signez l'assembly qui contient la classe d'hébergement (appelée Sandboxer dans cet exemple) qui appelle le code non fiable.Sign the assembly that contains the hosting class (named Sandboxer in this example) that calls the untrusted code. Ajouter le StrongName utilisé pour signer l'assembly au tableau StrongName du paramètre fullTrustAssemblies paramètre de l'appel CreateDomain.Add the StrongName used to sign the assembly to the StrongName array of the fullTrustAssemblies parameter of the CreateDomain call. La classe d'hébergement doit être exécutée avec un niveau de confiance totale pour permettre l'exécution du code de confiance partielle ou offrir des services à l'application de confiance partielle.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. Voici comment lire le StrongName d'un assembly :This is how you read the StrongName of an assembly:

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

    Les assemblys .NET Framework tels que mscorlib et System.dll n'ont pas à être ajoutés à la liste de confiance totale, car ils sont chargés avec un niveau de confiance totale à partir du 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. Initialisez le paramètre AppDomainSetup de la méthode CreateDomain.Initialize the AppDomainSetup parameter of the CreateDomain method. Ce paramètre vous permet de contrôler la plupart des paramètres du nouveau AppDomain.With this parameter, you can control many of the settings of the new AppDomain. La propriété ApplicationBase est un paramètre important qui doit être différent de la propriété ApplicationBase pour le AppDomain de l'application d'hébergement.The ApplicationBase property is an important setting, and should be different from the ApplicationBase property for the AppDomain of the hosting application. Si les paramètres ApplicationBase sont les mêmes, l'application de confiance partielle peut amener l'application d'hébergement à charger (avec un niveau de confiance totale) une exception définie par ses soins, et donc l'exploiter.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. Cela fait partie des raisons pour lesquelles un Catch (exception) n'est pas recommandé.This is another reason why a catch (exception) is not recommended. En configurant la base d'application de l'hôte différemment de la base d'application de l'application bac à sable (sandbox), vous réduisez les risques d'attaques.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. Appelez la surcharge de méthode CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) pour créer le domaine d'application à l'aide des paramètres spécifiés.Call the CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) method overload to create the application domain using the parameters we have specified.

    La signature de cette méthode est :The signature for this method is:

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

    Informations supplémentaires :Additional information:

    • Il s'agit de la seule surcharge de la méthode CreateDomain prenant un PermissionSet comme paramètre, et donc la seule surcharge qui vous permet de charger une application dans un paramètre de confiance partielle.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.

    • Le paramètre evidence n'est pas utilisé pour calculer un jeu d'autorisations, mais pour être identifié par les autres fonctionnalités du .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.

    • La définition de la propriété ApplicationBase du paramètre info est obligatoire pour cette surcharge.Setting the ApplicationBase property of the info parameter is mandatory for this overload.

    • Le paramètre fullTrustAssemblies possède le mot clé params, ce qui signifie qu'il n'est pas nécessaire de créer un tableau StrongName.The fullTrustAssemblies parameter has the params keyword, which means that it is not necessary to create a StrongName array. Passer 0, 1 ou plusieurs noms forts comme paramètres est autorisé.Passing 0, 1, or more strong names as parameters is allowed.

    • Le code servant à créer le domaine d'application est le suivant :The code to create the application domain is:

    AppDomain newDomain = AppDomain.CreateDomain("Sandbox", null, adSetup, permSet, fullTrustAssembly);  
    
  5. Chargez le code dans le AppDomain bac à sable (sandbox) que vous avez créé.Load the code into the sandboxing AppDomain that you created. Cette opération peut être réalisée de deux manières :This can be done in two ways:

    La seconde méthode est préférable, car elle simplifie le passage des paramètres à la nouvelle instance AppDomain.The second method is preferable, because it makes it easier to pass parameters to the new AppDomain instance. La méthode CreateInstanceFrom fournit deux fonctionnalités importantes :The CreateInstanceFrom method provides two important features:

    • Vous pouvez utiliser une base de code qui pointe vers un emplacement qui ne contient pas votre assembly.You can use a code base that points to a location that does not contain your assembly.

    • Vous pouvez effectuer la création sous un Assert pour la confiance totale (PermissionState.Unrestricted), ce qui vous permet de créer une instance d'une classe critique.You can do the creation under an Assert for full-trust (PermissionState.Unrestricted), which enables you to create an instance of a critical class. (Cela se produit chaque fois que votre assembly n’a pas de marquages de transparence et qu’il est chargé avec un niveau de confiance totale.) Par conséquent, vous devez veiller à créer uniquement le code que vous approuvez avec cette fonction, et nous vous recommandons de créer uniquement des instances de classes de confiance totale dans le nouveau domaine d’application.(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 );  
    

    Pour créer une instance d’une classe dans un nouveau domaine, la classe doit étendre la MarshalByRefObject classe.To create an instance of a class in a new domain, the class must extend the MarshalByRefObject class.

    class Sandboxer:MarshalByRefObject  
    
  6. Désencapsulez la nouvelle instance de domaine dans une référence de ce domaine.Unwrap the new domain instance into a reference in this domain. Cette référence est utilisée pour exécuter le code non fiable.This reference is used to execute the untrusted code.

    Sandboxer newDomainInstance = (Sandboxer) handle.Unwrap();  
    
  7. Appelez la méthode ExecuteUntrustedCode dans l'instance de la classe Sandboxer que vous venez de créer.Call the ExecuteUntrustedCode method in the instance of the Sandboxer class you just created.

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

    Cet appel est exécuté dans le domaine d'application bac à sable (sandbox), qui possède des autorisations restreintes.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 est utilisé pour obtenir le handle d'une méthode dans l'assembly de niveau de confiance partielle.System.Reflection is used to get a handle of a method in the partially trusted assembly. Le handle permet d'exécuter du code d'une façon sécurisée avec les autorisations minimales.The handle can be used to execute code in a safe way with minimum permissions.

    Dans le code précédent, notez Assert pour l'autorisation de confiance totale avant l'affichage de SecurityException.In the previous code, note the Assert for the full-trust permission before printing the SecurityException.

    new PermissionSet(PermissionState.Unrestricted).Assert()  
    

    L'assertion de confiance totale permet d'obtenir les informations détaillées de SecurityException.The full-trust assert is used to obtain extended information from the SecurityException. Sans Assert, la méthode ToString de SecurityException détecte que du code de niveau de confiance partielle se trouve sur la pile et restreint les informations retournées.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. Cela peut provoquer des problèmes de sécurité si le code de confiance partielle peut lire ces informations. Cependant, le risque est atténué par le fait de ne pas accorder 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'assertion de confiance totale doit être utilisée avec modération et uniquement quand vous êtes sûr de ne pas autoriser du code à passer du niveau de confiance partielle au niveau de confiance totale.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. En règle générale, n'appelez pas de code non fiable dans la même fonction et après avoir appelé une assertion de confiance 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. Nous vous conseillons de toujours rétablir l'assertion quand vous avez terminé de l'utiliser.It is good practice to always revert the assert when you have finished using it.

ExempleExample

L'exemple suivant implémente la procédure de la section précédente.The following example implements the procedure in the previous section. Dans l'exemple, un projet nommé Sandboxer dans une solution Visual Studio contient également un projet nommé UntrustedCode, qui implémente 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. Ce scénario suppose que vous avez téléchargé un assembly de bibliothèque qui contient une méthode censée retourner la valeur true ou false pour indiquer si le nombre que vous avez fourni est un nombre de 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. À la place, la méthode essaie de lire un fichier de votre ordinateur.Instead, the method attempts to read a file from your computer. L'exemple suivant illustre le code non fiable.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'exemple suivant montre le code de l'application Sandboxer qui exécute le code non fiable.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();  
        }  
    }  
}  

Voir aussiSee also