Share via


방법: 샌드박스에서 부분 신뢰 코드 실행

업데이트: 2007년 11월

샌드박싱은 응용 프로그램에 부여된 코드 액세스 권한을 제한하는 제한된 보안 환경에서 응용 프로그램을 실행하는 절차입니다. 예를 들어, Internet Explorer로 다운로드한 컨트롤은 Internet 권한 집합을 사용하여 실행되고 LAN(Local Area Network)의 공유에 있는 응용 프로그램은 LocalIntranet 권한 집합을 사용하여 사용자 컴퓨터에서 실행됩니다. 이러한 권한에 대한 자세한 내용은 명명된 권한 집합을 참조하십시오.

샌드박싱을 사용하면 컴퓨터에 다운로드한 부분 신뢰 응용 프로그램을 실행할 수 있습니다. 또한 샌드박싱을 사용하여 배포하려는 응용 프로그램이 인트라넷과 같은 부분 신뢰 환경에서 실행될 수 있는지 테스트할 수도 있습니다. CAS(코드 액세스 보안) 및 샌드박싱에 대한 자세한 내용은 MSDN(Microsoft Developer Network)에서 Find를 참조하십시오.

CreateDomain(String, Evidence, String, String, Boolean, AppDomainInitializer, array<String[]) 메서드 오버로드를 사용하여 샌드박스에서 실행되는 응용 프로그램에 대한 권한 집합을 지정할 수 있습니다. 이 오버로드를 사용하면 응용 프로그램에 부여된 권한 즉, 원하는 코드 액세스 보안의 정확한 수준을 제공하는 권한을 지정할 수 있습니다. 이 오버로드는 표준 CAS 정책을 사용하지 않습니다. 따라서 컴퓨터 정책이 적용되지 않습니다. 예를 들어, 호출된 어셈블리가 강력한 이름 키로 서명되고 사용자 지정 코드 그룹이 이 강력한 이름에 대해 존재하는 경우 코드 그룹이 적용되지 않습니다. 이 오버로드를 사용하여 로드된 어셈블리는 지정된 권한 부여 설정만 갖거나 완전히 신뢰될 수 있습니다. 전역 어셈블리 캐시나 완전 신뢰 목록에 있는 어셈블리는 완전한 신뢰를 받습니다. 그러나 완전히 신뢰되는 어셈블리를 대상으로 하면 샌드박스가 사용되지 않습니다.

오버로드에는 다음과 같은 시그니처가 있습니다.

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

CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, array<StrongName[]) 메서드 오버로드의 매개 변수는 AppDomain의 이름, 어셈블리에 대한 증명 정보, 샌드박스에 대한 응용 프로그램 기준을 식별하는 AppDomainSetup 개체, 사용할 권한 집합 및 신뢰되는 어셈블리의 강력한 이름을 지정합니다.

info 매개 변수에 지정된 응용 프로그램 기준은 호스팅 응용 프로그램에 대한 응용 프로그램 기준이면 안 됩니다. 그렇지 않으면 호스팅된 어셈블리가 Load 메서드를 사용하여 부분 신뢰 호출자의 호출을 검색하도록 설계되지 않았을 수 있는 폴더로 다른 어셈블리를 로드할 수 있습니다.

grantSet 매개 변수의 경우 명시적으로 만든 권한 집합이나 Internet 또는 LocalIntranet 같은 명명된 권한 집합 중 하나를 지정할 수 있습니다. 이 항목의 뒷부분에 나오는 완전한 예제에서는 사용자 지정 권한 집합을 만드는 대신 명명된 권한 집합을 사용하는 방법을 보여 줍니다.

대부분의 AppDomain 로드와 달리 securityInfo 매개 변수에서 제공하는 어셈블리에 대한 대한 증명 정보는 권한 부여 설정을 결정하는 데 사용되지 않는 대신 grantSet 매개 변수에서 독립적으로 지정됩니다. 그러나 증명 정보는 격리된 저장소 확인과 같은 다른 용도로 사용될 수 있습니다.

샌드박스에서 응용 프로그램을 실행하려면

  1. 응용 프로그램에 부여할 권한 집합을 만듭니다.

    참고:

    이 예제의 응용 프로그램에는 실행을 위한 Execution 권한과 콘솔에 쓰기 위한 UIPermission이 필요합니다. 다음 코드에서는 이러한 권한이 포함된 새 권한 집합을 만듭니다. 또는 LocalIntranet 같은 기존의 명명된 권한 집합을 사용할 수 있습니다. 명명된 권한 집합을 사용하는 방법에 대한 예제는 이 항목의 뒷부분에 나오는 "예제" 단원을 참조하십시오.

    PermissionSet pset = new PermissionSet(PermissionState.None);
    pset.AddPermission(new      SecurityPermission(SecurityPermissionFlag.Execution));
    pset.AddPermission(new UIPermission(PermissionState.Unrestricted));
    
  2. 샌드박스로 사용할 폴더를 초기화합니다. 이때 호스팅 응용 프로그램이 사용하고 있는 폴더를 사용하면 안 됩니다. 호스팅 폴더에 응용 프로그램을 저장하면 호스팅 어셈블리가 이 폴더에 있는 모든 어셈블리를 로드할 수 있습니다.

    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. CreateDomain(String, Evidence, String, String, Boolean, AppDomainInitializer, array<String[]) 메서드 오버로드를 사용하여 도메인을 만듭니다. 이 경우 부모 어셈블리에 대한 증명 정보와 강력한 이름이 지정됩니다. GetStrongName 메서드의 코드는 이 항목의 뒷부분에 나오는 "예제" 단원을 참조하십시오.

    // Create the sandboxed application domain.
    AppDomain sandbox = AppDomain.CreateDomain(
    "Sandboxed Domain",
    AppDomain.CurrentDomain.Evidence,
    ads, pset, GetStrongName(Assembly.GetExecutingAssembly()));
    
  4. 응용 프로그램을 실행합니다.

    sandbox.ExecuteAssemblyByName("HelloWorld");
    

예제

다음 예제는 이전 단원의 절차를 구현하는 완전한 예제입니다. 이 예제에서는 인트라넷 환경에 부여된 것과 동일한 권한을 사용하여 응용 프로그램을 실행하는 방법을 보여 줍니다. 이 예제의 HelloWorld.exe 어셈블리를 바꾸려면 테스트 응용 프로그램을 직접 만들어야 합니다.

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

    }
}