Sdílet prostřednictvím


Gewusst wie: Ausführen von teilweise vertrauenswürdigem Code in einer Sandbox

Aktualisiert: November 2007

Beim Verwenden einer Sandbox wird eine Anwendung in einer beschränkten Sicherheitsumgebung ausgeführt, wodurch die gewährten Codezugriffsberechtigungen eingeschränkt sind. Beispielsweise werden nach Internet Explorer heruntergeladene Steuerelemente mit dem Internet-Berechtigungssatz ausgeführt. Anwendungen, die sich auf freigegebenen Speicherorten im lokalen Netzwerk befinden, werden auf dem Computer mit dem LocalIntranet-Berechtigungssatz ausgeführt. (Weitere Informationen zu diesen Berechtigungen finden Sie unter Benannte Berechtigungssätze.)

Mithilfe einer Sandbox können Sie teilweise vertrauenswürdige Anwendungen ausführen, die Sie auf den Computer heruntergeladen haben. Darüber hinaus können Sie mit einer Sandbox zu verteilende Anwendungen testen, die in teilweise vertrauenswürdigen Umgebungen wie dem Intranet ausgeführt werden. Umfassende Informationen zu Code Access Security (CAS) und zur Verwendung der Sandbox finden Sie auf der MSDN-Website (Microsoft Developer Network) unter folgendem Link: Find Out What's New with Code Access Security in the .Net Framework 2.0.

Sie können mit der CreateDomain(String, Evidence, String, String, Boolean, AppDomainInitializer, array<String[])-Methodenüberladung den Berechtigungssatz für Anwendungen festlegen, die in einer Sandbox ausgeführt werden. Durch die Überladung können Sie die einer Anwendung gewährten Berechtigungen festlegen und auf diese Weise genau die gewünschte Ebene der Codezugriffssicherheit bereitstellen. Eine Standard-CAS-Richtlinie (Computerrichtlinie wird nicht übernommen) wird nicht angewendet. Wenn z. B. die aufgerufene Assembly mit einem Schlüssel mit einem starken Namen signiert wird und für den starken Namen eine benutzerdefinierte Codegruppe vorhanden ist, wird die Codegruppe nicht angewendet. Assemblys, die mithilfe dieser Überladung geladen werden, können entweder über den festgelegten Berechtigungssatz oder über volle Vertrauenswürdigkeit verfügen. Der Assembly wird volle Vertrauenswürdigkeit gewährt, wenn sie sich im globalen Assemblycache oder auf der Liste der vollständig vertrauenswürdigen Assemblys befindet. Das Abzielen auf eine vollständig vertrauenswürdige Assembly umgeht jedoch die Verwendung einer Sandbox.

Die Überladung hat folgende Signatur:

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

Die Parameter für die CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, array<StrongName[])-Methodenüberladung bestimmen den Namen der AppDomain, der Beweis für die Assembly, das AppDomainSetup-Objekt, das die Anwendungsbasis für die Sandbox, den zu verwendenden Berechtigungssatz und den starken Namen für vertrauenswürdige Assemblys identifiziert.

Die im info-Parameter festgelegte Anwendungsbasis darf nicht die Anwendungsbasis für die Hostanwendung sein. Wenn sie es ist, kann die gehostete Assembly mit der Load-Methode andere Assemblys in den Ordner laden, der möglicherweise nicht dafür entworfen wurde, die Aufrufe teilweise vertrauenswürdiger Aufrufer zu erkennen.

Sie können für den grantSet-Parameter einen explizit dafür erstellten Berechtigungssatz festlegen oder einen der benannten Berechtigungssätze wie Internet oder LocalIntranet. In dem in diesem Thema bereitgestellten Beispiel wird veranschaulicht, wie benannte Berechtigungssätze verwendet werden, sodass das Erstellen benutzerdefinierter Berechtigungssätze nicht erforderlich ist.

Im Gegensatz zu den meisten AppDomain-Ladungen wird der Beweis für die Assembly (der durch den securityInfo-Parameter bereitgestellt wird) nicht zum Bestimmen des Berechtigungssatzes verwendet. Stattdessen wird er unabhängig vom grantSet-Parameter angegeben. Der Beweis kann jedoch für andere Zwecke, z. B. zum Bestimmen des isolierten Speichers, verwendet werden.

So führen Sie eine Anwendung in einer Sandbox aus

  1. Erstellen Sie den Berechtigungssatz, der der Anwendung gewährt werden soll.

    Hinweis:

    In diesem Beispiel ist zum Ausführen der Anwendung die Execution-Berechtigung und zum Schreiben an die Konsole die UIPermission-Berechtigung erforderlich. Mit dem folgenden Code wird ein neuer Berechtigungssatz erstellt, der diese Berechtigungen enthält. Alternativ können Sie einen vorhandenen benannten Berechtigungssatz verwenden, z. B. LocalIntranet. Ein Beispiel zur Verwendung von benannten Berechtigungen finden Sie weiter unten in diesem Thema im Abschnitt "Beispiel".

    PermissionSet pset = new PermissionSet(PermissionState.None);
    pset.AddPermission(new      SecurityPermission(SecurityPermissionFlag.Execution));
    pset.AddPermission(new UIPermission(PermissionState.Unrestricted));
    
  2. Initialisieren Sie den Ordner, der als Sandbox verwendet wird. Verwenden Sie nicht den Ordner, den die Hostanwendung verwendet. Wenn Sie die Anwendung im Hostordner platzieren, kann die Hostassembly beliebige Assemblys in den Ordner laden.

    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. Verwenden Sie die CreateDomain(String, Evidence, String, String, Boolean, AppDomainInitializer, array<String[])-Methodenüberladung, um die Domäne zu erstellen. In diesem Fall werden der Beweis und der starke Name für die übergeordnete Assembly angegeben. Den Code für die GetStrongName-Methode finden Sie weiter unten in diesem Thema im Abschnitt "Beispiel".

    // Create the sandboxed application domain.
    AppDomain sandbox = AppDomain.CreateDomain(
    "Sandboxed Domain",
    AppDomain.CurrentDomain.Evidence,
    ads, pset, GetStrongName(Assembly.GetExecutingAssembly()));
    
  4. Führen Sie die Anwendung aus.

    sandbox.ExecuteAssemblyByName("HelloWorld");
    

Beispiel

In dem folgenden vollständigen Beispiel wird die Implementierung der Prozedur aus dem vorherigen Abschnitt veranschaulicht. In diesem Beispiel wird dargestellt, wie Sie eine Anwendung mit denselben Berechtigungen ausführen, die ihr in einer Intranetumgebung gewährt würden. Sie müssen eine eigene Testanwendung erstellen, um die HelloWorld.exe-Assembly im Beispiel zu ersetzen.

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

    }
}