Partager via


Comment : exécuter du code d'un niveau de confiance partiel dans un bac à sable (sandbox)

Mise à jour : novembre 2007

Le sandboxing consiste à exécuter une application dans un environnement de sécurité restreint qui limite les autorisations d'accès du code accordées. Par exemple, les contrôles téléchargés sur Internet Explorer s'exécutent à l'aide du jeu d'autorisations Internet. Les applications qui se trouvent sur les partages de votre réseau local s'exécutent sur votre ordinateur à l'aide du jeu d'autorisations LocalIntranet. (Pour plus d'informations sur ces autorisations, consultez Jeux d'autorisations nommés.)

Vous pouvez utiliser le sandboxing pour exécuter des applications d'un niveau de confiance partiel téléchargées sur votre ordinateur. Vous pouvez également utiliser le sandboxing pour tester des applications à distribuer qui s'exécutent avec un niveau de confiance partiel dans des environnements tels que l'intranet. Pour une description complète de la sécurité d'accès du code (CAS) et du sandboxing, consultez la page Find (en anglais) sur MSDN (Microsoft Developer Network).

Vous pouvez utiliser la surcharge de la méthode CreateDomain(String, Evidence, String, String, Boolean, AppDomainInitializer, array<String[]) pour définir le jeu d'autorisations des applications qui s'exécutent dans un « bac à sable » (sandbox). Cette surcharge vous permet de définir les autorisations accordées à une application et fournit ainsi le niveau exact de sécurité d'accès du code désiré. La stratégie standard CAS n'est pas utilisée (la stratégie de l'ordinateur n'est pas appliquée). Par exemple, si l'assembly appelé est signé avec une clé de nom fort et si un groupe de codes personnalisés existe pour ce nom fort, le groupe de codes ne s'applique pas. Les assemblys chargés à l'aide de cette surcharge peuvent disposer soit uniquement du jeu d'autorisations, soit de la confiance totale. La confiance totale est accordée à l'assembly seulement dans le Global Assembly Cache ou dans la liste de confiance totale. Toutefois, si vous ciblez un assembly doté d'une confiance totale, vous outrepassez l'utilisation d'un « bac à sable » (sandbox).

La surcharge possède la signature suivante :

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

Les paramètres de surcharge de la méthode CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, array<StrongName[]) définissent le nom de la AppDomain, la preuve de l'assembly, l'objet AppDomainSetup qui identifie la base de l'application pour le « bac à sable » (sandbox), le jeu d'autorisations à utiliser et le nom fort des assemblys fiables.

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. Si cela est le cas, l'assembly hébergé est en mesure d'utiliser la méthode Load pour charger d'autres assemblys dans ce dossier qui n'a pas peut-être pas été conçu pour détecter des appels d'appelants dotés d'une confiance partielle.

Pour le paramètre grantSet, vous pouvez définir soit un jeu d'autorisations que vous avez créé explicitement, soit l'un des jeux d'autorisations nommés tels que Internet ou LocalIntranet. L'exemple complet fourni dans cette rubrique décrit comment utiliser des jeux d'autorisations nommés au lieu de créer un jeu d'autorisations personnalisé.

Contrairement à la plupart des charges AppDomain, la preuve pour l'assembly (fournie par le paramètre securityInfo ) n'est pas utilisée pour déterminer le jeu d'autorisations. Il est spécifié indépendamment par le paramètre grantSet. Toutefois, la preuve peut être utilisée à d'autres fins, pour déterminer le stockage isolé par exemple.

Pour exécuter une application dans un bac à sable (sandbox)

  1. Créez le jeu d'autorisations à accorder à l'application.

    Remarque :

    L'application de cet exemple nécessite l'exécution de l'autorisation Execution et l'écriture de UIPermission sur la console. Le code suivant crée un jeu d'autorisations à l'aide de ces autorisations. Vous pouvez également utiliser un jeu d'autorisations nommé existant, tel que LocalIntranet. Pour obtenir un exemple de l'utilisation d'un jeu d'autorisations nommé, consultez la section « Exemple » de cette rubrique.

    PermissionSet pset = new PermissionSet(PermissionState.None);
    pset.AddPermission(new      SecurityPermission(SecurityPermissionFlag.Execution));
    pset.AddPermission(new UIPermission(PermissionState.Unrestricted));
    
  2. Initialisez le dossier à utiliser comme bac à sable (sandbox). N'utilisez pas le dossier utilisé par votre application d'hébergement. Si vous placez l'application dans le dossier hébergement, l'assembly d'hébergement pourra charger n'importe quel assembly dans le dossier.

    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);
    
  3. Utilisez la surcharge de la méthode CreateDomain(String, Evidence, String, String, Boolean, AppDomainInitializer, array<String[]) pour créer le domaine. Dans ce cas, la preuve et le nom fort de l'assembly parent sont définis. Consultez la section « Exemple » de cette rubrique pour le code de la méthode GetStrongName.

    // Create the sandboxed application domain.
    AppDomain sandbox = AppDomain.CreateDomain(
    "Sandboxed Domain",
    AppDomain.CurrentDomain.Evidence,
    ads, pset, GetStrongName(Assembly.GetExecutingAssembly()));
    
  4. Exécutez l'application.

    sandbox.ExecuteAssemblyByName("HelloWorld");
    

Exemple

L'exemple suivant est un exemple complet qui implémente la procédure de la section précédente. Cet exemple montre comment lancer une application en utilisant les autorisations qui seraient accordées dans un environnement intranet. Vous devez créer votre propre application de test pour remplacer l'assembly HelloWorld.exe de l'exemple.

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;
        }

    }
}