안내: 부분 신뢰 시나리오에서 코드 내보내기
리플렉션 내보내기에서는 전체 또는 부분 신뢰에서 동일한 API 집합을 사용하지만 일부 기능에는 부분적으로 신뢰할 수 있는 코드에서 특별한 권한이 필요합니다. 또한 Reflection Emit에는 부분적 신뢰와 보안 투명 어셈블리에서 사용하도록 설계된 익명으로 호스팅되는 동적 메서드 기능이 포함되어 있습니다.
비고
.NET Framework 3.5 이전에는 코드를 내보내기 위해 ReflectionPermission가 ReflectionPermissionFlag.ReflectionEmit 플래그와 함께 필요했습니다. 이 권한은 기본적으로 FullTrust
및 명명된 사용 권한 집합에 Intranet
포함되지만 Internet
권한 집합에는 포함되지 않습니다. 따라서 SecurityCriticalAttribute 특성을 가지고 있고 ReflectionEmit를 위한 Assert 메서드를 실행할 경우에만 라이브러리는 부분 신뢰에서 사용할 수 있습니다. 코딩 오류로 인해 보안 허점이 발생할 수 있으므로 이러한 라이브러리에는 신중한 보안 검토가 필요합니다. .NET Framework 3.5에서는 코드 생성이 기본적으로 권한 있는 작업이 아니므로 보안 요구를 실행하지 않고 부분 신뢰 시나리오에서 코드를 내보냅니다. 즉, 생성된 코드는 해당 코드를 내보내는 어셈블리보다 더 이상 권한이 없습니다. 이렇게 하면 코드를 내보내는 라이브러리가 보안 투명하고 ReflectionEmit어설션할 필요가 없으므로 보안 라이브러리를 작성할 때는 철저한 보안 검토가 필요하지 않습니다.
이 단계별 설명에서는 다음 작업을 설명합니다.
부분적으로 신뢰할 수 있는 코드테스트하기 위한 간단한 샌드박스를 설정합니다.
중요합니다
이는 부분 신뢰의 코드를 실험하는 간단한 방법입니다. 신뢰할 수 없는 위치에서 실제로 제공되는 코드를 실행하려면 방법: 샌드박스부분적으로 신뢰할 수 있는 코드 실행을 참조하세요.
익명으로 호스트된 동적 메서드를 사용하여 부분 신뢰코드를 내보내고 실행합니다.
부분 신뢰 시나리오에서 코드를 내보내는 것에 대한 자세한 내용은 리플렉션 이밋의 보안 문제 과을 참조하세요.
이러한 절차에 표시된 코드의 전체 목록은 이 연습의 끝에 예제 섹션을 참조하세요.
부분적으로 신뢰할 수 있는 위치 설정
다음 두 절차에서는 부분 신뢰로 코드를 테스트할 수 있는 위치를 설정하는 방법을 보여 줍니다.
첫 번째 절차에서는 코드에 인터넷 권한이 부여되는 샌드박스 애플리케이션 도메인을 만드는 방법을 보여 줍니다.
두 번째 절차에서는 부분적으로 신뢰할 수 있는 애플리케이션 도메인에 ReflectionPermissionFlag.RestrictedMemberAccess 플래그가 있는 ReflectionPermission 추가하여 동일하거나 낮은 신뢰 어셈블리의 프라이빗 데이터에 액세스할 수 있도록 하는 방법을 보여 줍니다.
샌드박스 애플리케이션 도메인 만들기
부분 신뢰로 어셈블리가 실행되는 애플리케이션 도메인을 만들려면 AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) 메서드 오버로드를 사용하여 애플리케이션 도메인을 만들어 어셈블리에 부여할 사용 권한 집합을 지정해야 합니다. 권한 부여 집합을 지정하는 가장 쉬운 방법은 보안 정책에서 명명된 권한 집합을 검색하는 것입니다.
다음 절차에서는 부분 신뢰로 코드를 실행하는 샌드박스 애플리케이션 도메인을 만들어 내보낸 코드가 공용 형식의 공용 멤버에만 액세스할 수 있는 시나리오를 테스트합니다. 이후 절차에서는 RestrictedMemberAccess추가하여 내보낸 코드가 동일하거나 더 적은 권한을 부여받은 어셈블리의 비공유 형식 및 멤버에 액세스할 수 있는 시나리오를 테스트하는 방법을 보여 줍니다.
부분 신뢰가 있는 애플리케이션 도메인을 만들려면
샌드박스 애플리케이션 도메인의 어셈블리에 부여할 권한 집합을 만듭니다. 이 경우 인터넷 영역의 사용 권한 집합이 사용됩니다.
Evidence ev = new Evidence(); ev.AddHostEvidence(new Zone(SecurityZone.Internet)); PermissionSet pset = new NamedPermissionSet("Internet", SecurityManager.GetStandardSandbox(ev));
Dim ev As New Evidence() ev.AddHostEvidence(new Zone(SecurityZone.Internet)) Dim pset As New NamedPermissionSet("Internet", SecurityManager.GetStandardSandbox(ev))
애플리케이션 경로를 사용하여 애플리케이션 도메인을 초기화하는 AppDomainSetup 개체를 만듭니다.
중요합니다
간단히 하기 위해 이 코드 예제에서는 현재 폴더를 사용합니다. 인터넷에서 제공되는 코드를 실제로 실행하려면 신뢰할 수 없는 코드에 별도의 폴더를 사용하고, 이와 관련하여 방법: 샌드박스에서 부분적으로 신뢰할 수 있는 코드를 실행하는 방법에 설명된 대로 하십시오.
AppDomainSetup adSetup = new AppDomainSetup(); adSetup.ApplicationBase = ".";
Dim adSetup As New AppDomainSetup() adSetup.ApplicationBase = "."
애플리케이션 도메인에서 실행되는 모든 어셈블리에 대한 애플리케이션 도메인 설정 정보 및 권한 부여 집합을 지정하여 애플리케이션 도메인을 만듭니다.
AppDomain ad = AppDomain.CreateDomain("Sandbox", ev, adSetup, pset, null);
Dim ad As AppDomain = AppDomain.CreateDomain("Sandbox", ev, adSetup, pset, Nothing)
AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) 메서드 오버로드의 마지막 매개 변수를 사용하면 애플리케이션 도메인의 권한 부여 집합 대신 완전 신뢰를 부여할 어셈블리 집합을 지정할 수 있습니다. 이러한 어셈블리는 전역 어셈블리 캐시에 있으므로 애플리케이션에서 사용하는 .NET Framework 어셈블리를 지정할 필요가 없습니다. 글로벌 어셈블리 캐시의 어셈블리는 항상 전적으로 신뢰됩니다. 이 매개 변수를 사용하여 전역 어셈블리 캐시에 없는 강력한 이름의 어셈블리를 지정할 수 있습니다.
샌드박스 도메인에 RestrictedMemberAccess 추가
호스트 애플리케이션은 익명으로 호스트되는 동적 메서드가 코드를 내보내는 어셈블리의 신뢰 수준과 같거나 작은 신뢰 수준이 있는 어셈블리의 프라이빗 데이터에 액세스할 수 있도록 허용할 수 있습니다. JIT(Just-In-Time) 가시성 검사를 건너뛰는 이 제한된 기능을 활성화하기 위해 호스트 애플리케이션은 ReflectionPermissionFlag.RestrictedMemberAccess(RMA) 플래그가 포함된 ReflectionPermission 객체를 권한 부여 집합에 추가합니다.
예를 들어 호스트는 인터넷 애플리케이션에 인터넷 사용 권한과 RMA를 부여하여 인터넷 애플리케이션이 자체 어셈블리의 프라이빗 데이터에 액세스하는 코드를 내보낼 수 있도록 할 수 있습니다. 액세스는 신뢰도가 같거나 낮은 어셈블리로 제한되므로 인터넷 애플리케이션은 .NET Framework 어셈블리와 같이 완전히 신뢰할 수 있는 어셈블리의 멤버에 액세스할 수 없습니다.
비고
권한 상승을 방지하기 위해 익명으로 호스트되는 동적 메서드를 생성할 때 내보내는 어셈블리에 대한 스택 정보가 포함됩니다. 메서드가 호출되면 스택 정보가 확인됩니다. 따라서 완전히 신뢰할 수 있는 코드에서 호출되는 익명으로 호스트된 동적 메서드는 여전히 내보내는 어셈블리의 신뢰 수준으로 제한됩니다.
부분 신뢰와 RMA를 사용하여 애플리케이션 도메인을 만들려면
RestrictedMemberAccess(RMA) 플래그를 사용하여 새 ReflectionPermission 개체를 만들고 PermissionSet.SetPermission 메서드를 사용하여 권한 부여 집합에 권한을 추가합니다.
pset.SetPermission( new ReflectionPermission( ReflectionPermissionFlag.RestrictedMemberAccess));
pset.SetPermission( _ New ReflectionPermission( _ ReflectionPermissionFlag.RestrictedMemberAccess))
AddPermission 메서드는 아직 포함되지 않은 경우 권한 부여 집합에 권한을 추가합니다. 권한 집합에 사용 권한이 이미 포함되어 있으면 지정된 플래그가 기존 권한에 추가됩니다.
비고
RMA는 익명으로 호스트되는 동적 메서드의 기능입니다. 일반적인 동적 메서드가 JIT 표시 유형 검사를 건너뛰는 경우 내보낸 코드에는 완전 신뢰가 필요합니다.
애플리케이션 도메인 설정 정보 및 권한 부여 집합을 지정하여 애플리케이션 도메인을 만듭니다.
ad = AppDomain.CreateDomain("Sandbox2", ev, adSetup, pset, null);
ad = AppDomain.CreateDomain("Sandbox2", ev, adSetup, pset, Nothing)
샌드박스 애플리케이션 도메인에서 코드 실행
다음 절차에서는 애플리케이션 도메인에서 실행할 수 있는 메서드를 사용하여 클래스를 정의하는 방법, 도메인에서 클래스의 인스턴스를 만드는 방법 및 해당 메서드를 실행하는 방법을 설명합니다.
애플리케이션 도메인에서 메서드를 정의하고 실행하려면
MarshalByRefObject에서 파생된 클래스를 정의합니다. 이렇게 하면 다른 애플리케이션 도메인에서 클래스의 인스턴스를 만들고 애플리케이션 도메인 경계를 넘어 메서드를 호출할 수 있습니다. 이 예제의 클래스 이름은
Worker
.public class Worker : MarshalByRefObject {
Public Class Worker Inherits MarshalByRefObject
실행하려는 코드가 포함된 공용 메서드를 정의합니다. 이 예제에서 코드는 간단한 동적 메서드를 내보내고, 메서드를 실행하는 대리자를 만들고, 대리자를 호출합니다.
public void SimpleEmitDemo() { DynamicMethod meth = new DynamicMethod("", null, null); ILGenerator il = meth.GetILGenerator(); il.EmitWriteLine("Hello, World!"); il.Emit(OpCodes.Ret); Test1 t1 = (Test1) meth.CreateDelegate(typeof(Test1)); t1(); }
Public Sub SimpleEmitDemo() Dim meth As DynamicMethod = new DynamicMethod("", Nothing, Nothing) Dim il As ILGenerator = meth.GetILGenerator() il.EmitWriteLine("Hello, World!") il.Emit(OpCodes.Ret) Dim t1 As Test1 = CType(meth.CreateDelegate(GetType(Test1)), Test1) t1() End Sub
주 프로그램에서 어셈블리의 표시 이름을 가져옵니다. 이 이름은 샌드박스 애플리케이션 도메인에서
Worker
클래스의 인스턴스를 만들 때 사용됩니다.String asmName = typeof(Worker).Assembly.FullName;
Dim asmName As String = GetType(Worker).Assembly.FullName
주 프로그램에서 이 연습의 첫 번째 프로시저에 설명된 대로 샌드박스 애플리케이션 도메인을 만듭니다.
SimpleEmitDemo
메서드는 공용 메서드만 사용하므로Internet
사용 권한 집합에 사용 권한을 추가할 필요가 없습니다.주 프로그램에서 샌드박스 애플리케이션 도메인에
Worker
클래스의 인스턴스를 만듭니다.Worker w = (Worker) ad.CreateInstanceAndUnwrap(asmName, "Worker");
Dim w As Worker = _ CType(ad.CreateInstanceAndUnwrap(asmName, "Worker"), Worker)
CreateInstanceAndUnwrap 메서드는 대상 애플리케이션 도메인에 개체를 만들고 개체의 속성 및 메서드를 호출하는 데 사용할 수 있는 프록시를 반환합니다.
비고
Visual Studio에서 이 코드를 사용하는 경우 네임스페이스를 포함하도록 클래스의 이름을 변경해야 합니다. 기본적으로 네임스페이스는 프로젝트의 이름입니다. 예를 들어 프로젝트가 "PartialTrust"인 경우 클래스 이름은 "PartialTrust.Worker"여야 합니다.
SimpleEmitDemo
메서드를 호출하는 코드를 추가합니다. 호출은 애플리케이션 도메인 경계를 넘어 마샬링되고 코드는 샌드박스 애플리케이션 도메인에서 실행됩니다.w.SimpleEmitDemo();
w.SimpleEmitDemo()
익명으로 호스트된 동적 메서드 사용
익명으로 호스트되는 동적 메서드는 시스템에서 제공하는 투명한 어셈블리와 연결됩니다. 따라서 포함된 코드는 투명합니다. 반면에 일반적인 동적 메서드는 기존 모듈(연결된 형식에서 직접 지정 또는 유추 여부)과 연결되어야 하며 해당 모듈에서 해당 보안 수준을 가져와야 합니다.
비고
익명 호스팅을 제공하는 어셈블리와 동적 메서드를 연결하는 유일한 방법은 다음 절차에 설명된 생성자를 사용하는 것입니다. 익명 호스팅 어셈블리에서 모듈을 명시적으로 지정할 수 없습니다.
일반 동적 메서드는 연결된 모듈의 내부 멤버 또는 연결된 형식의 프라이빗 멤버에 액세스할 수 있습니다. 익명으로 호스트되는 동적 메서드는 다른 코드와 격리되므로 프라이빗 데이터에 액세스할 수 없습니다. 그러나 JIT 가시성 검사를 건너뛰어 개인 데이터에 대한 액세스 권한을 얻는 제한된 기능이 있습니다. 이 기능은 코드를 내보내는 어셈블리의 신뢰 수준과 같거나 작은 신뢰 수준이 있는 어셈블리로 제한됩니다.
권한 상승을 방지하기 위해 익명으로 호스트되는 동적 메서드를 생성할 때 내보내는 어셈블리에 대한 스택 정보가 포함됩니다. 메서드가 호출될 때 스택 정보가 확인됩니다. 완전히 신뢰할 수 있는 코드에서 호출되는 익명으로 호스트된 동적 메서드는 여전히 해당 메서드를 내보낸 어셈블리의 신뢰 수준으로 제한됩니다.
익명으로 호스트되는 동적 메서드를 사용하려면
연결된 모듈 또는 형식을 지정하지 않는 생성자를 사용하여 익명으로 호스트되는 동적 메서드를 만듭니다.
DynamicMethod meth = new DynamicMethod("", null, null); ILGenerator il = meth.GetILGenerator(); il.EmitWriteLine("Hello, World!"); il.Emit(OpCodes.Ret);
Dim meth As DynamicMethod = new DynamicMethod("", Nothing, Nothing) Dim il As ILGenerator = meth.GetILGenerator() il.EmitWriteLine("Hello, World!") il.Emit(OpCodes.Ret)
익명으로 호스트된 동적 메서드가 공용 형식 및 메서드만 사용하는 경우 제한된 멤버 액세스가 필요하지 않으며 JIT 표시 유형 검사를 건너뛸 필요가 없습니다.
동적 메서드를 내보내는 데 특별한 권한이 필요하지는 않지만 내보낸 코드에는 사용하는 형식 및 메서드에서 요구하는 권한이 필요합니다. 예를 들어 내보낸 코드가 파일에 액세스하는 메서드를 호출하는 경우 FileIOPermission필요합니다. 트러스트 수준에 해당 권한이 포함되지 않으면 내보낸 코드가 실행될 때 보안 예외가 throw됩니다. 여기에 표시된 코드는 Console.WriteLine 메서드만 사용하는 동적 메서드를 내보낸다. 따라서 부분적으로 신뢰할 수 있는 위치에서 코드를 실행할 수 있습니다.
또는 DynamicMethod(String, Type, Type[], Boolean) 생성자를 사용하고
restrictedSkipVisibility
매개 변수에 대한true
지정하여 JIT 표시 유형 검사를 건너뛰는 제한된 기능을 사용하여 익명으로 호스트되는 동적 메서드를 만듭니다.DynamicMethod meth = new DynamicMethod("", typeof(char), new Type[] { typeof(String) }, true);
Dim meth As New DynamicMethod("", _ GetType(Char), _ New Type() {GetType(String)}, _ True)
익명으로 호스트되는 동적 메서드는 내보내는 어셈블리의 신뢰 수준과 같거나 작은 신뢰 수준이 있는 어셈블리에서만 프라이빗 데이터에 액세스할 수 있다는 제한이 있습니다. 예를 들어 동적 메서드가 인터넷 트러스트를 사용하여 실행되는 경우 인터넷 트러스트를 사용하여 실행되는 다른 어셈블리의 프라이빗 데이터에 액세스할 수 있지만 .NET Framework 어셈블리의 프라이빗 데이터에는 액세스할 수 없습니다. .NET Framework 어셈블리는 전역 어셈블리 캐시에 설치되며 항상 완전히 신뢰할 수 있습니다.
익명으로 호스팅된 동적 메서드는 호스트 애플리케이션이 ReflectionPermissionFlag.RestrictedMemberAccess 플래그를 사용하여 ReflectionPermission을 부여해야만 JIT 가시성 검사를 건너뛰게 하는 이 제한 기능을 사용할 수 있습니다. 이 권한에 대한 요구는 메서드가 호출될 때 수행됩니다.
비고
내보내기 어셈블리에 대한 호출 스택 정보는 동적 메서드가 생성될 때 포함됩니다. 따라서 메서드를 호출하는 어셈블리 대신 내보내는 어셈블리의 사용 권한에 대해 요구가 이루어집니다. 이렇게 하면 내보낸 코드가 관리자 권한으로 실행되지 않습니다.
이 학습 과정의 끝에 있는 전체 코드 예제는 제한된 멤버 액세스의 사용법과 제약 사항을 보여줍니다. 해당
Worker
클래스에는 가시성 검사를 건너뛰는 제한된 기능을 사용하거나 사용하지 않고 익명으로 호스트되는 동적 메서드를 만들 수 있는 메서드가 포함되어 있으며, 이 예제에서는 신뢰 수준이 다른 애플리케이션 도메인에서 이 메서드를 실행한 결과를 보여 줍니다.비고
가시성 검사를 건너뛰는 제한된 기능은 익명으로 호스트되는 동적 메서드의 기능입니다. 일반적인 동적 메서드가 JIT 표시 유형 검사를 건너뛰는 경우 완전 신뢰가 부여되어야 합니다.
예시
설명
다음 코드 예제에서는 익명으로 호스트된 동적 메서드가 JIT 표시 유형 검사를 건너뛸 수 있도록 RestrictedMemberAccess 플래그를 사용하는 방법을 보여 주지만 대상 멤버가 코드를 내보내는 어셈블리보다 같거나 낮은 신뢰 수준에 있는 경우에만 사용할 수 있습니다.
이 예제에서는 애플리케이션 도메인 경계를 넘어 마샬링할 수 있는 Worker
클래스를 정의합니다. 클래스에는 동적 메서드를 내보내고 실행하는 두 개의 AccessPrivateMethod
메서드 오버로드가 있습니다. 첫 번째 오버로드는 Worker
클래스의 private PrivateMethod
메서드를 호출하는 동적 메서드를 내보내고 JIT 표시 유형 검사 유의 여부에 관계없이 동적 메서드를 내보낼 수 있습니다. 두 번째 오버로드는 String 클래스의 internal
속성(Visual Basic의Friend
속성)에 액세스하는 동적 메서드를 내보낸다.
이 예제에서는 도우미 메서드를 사용하여 Internet
권한으로 제한된 권한 부여 집합을 만든 다음 AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) 메서드 오버로드를 사용하여 애플리케이션 도메인을 만들어 도메인에서 실행되는 모든 코드에서 이 권한 부여 집합을 사용하도록 지정합니다. 이 예제에서는 애플리케이션 도메인에서 Worker
클래스의 인스턴스를 만들고 AccessPrivateMethod
메서드를 두 번 실행합니다.
AccessPrivateMethod
메서드가 처음 실행되면 JIT 표시 유형 검사가 적용됩니다. JIT 표시 유형 검사를 통해 프라이빗 메서드에 액세스할 수 없으므로 동적 메서드가 호출될 때 실패합니다.AccessPrivateMethod
메서드가 두 번째로 실행될 때 JIT 가시성 검사가 생략됩니다.Internet
권한 부여 집합에서 표시 유형 검사를 건너뛸 수 있는 충분한 권한을 부여하지 않으므로 동적 메서드가 컴파일될 때 실패합니다.
예제에서는 ReflectionPermission을(를) ReflectionPermissionFlag.RestrictedMemberAccess과 함께 권한 부여 집합에 추가합니다. 그런 다음, 도메인에서 실행되는 모든 코드에 새 권한 집합의 사용 권한이 부여되도록 지정하여 두 번째 도메인을 만듭니다. 이 예제에서는 새 애플리케이션 도메인에서 Worker
클래스의 인스턴스를 만들고 AccessPrivateMethod
메서드의 두 오버로드를 모두 실행합니다.
AccessPrivateMethod
메서드의 첫 번째 오버로드가 실행되며 JIT 가시성 검사가 건너뛰어집니다. 코드를 내보내는 어셈블리가 private 메서드를 포함하는 어셈블리와 동일하기 때문에 동적 메서드가 성공적으로 컴파일되고 실행됩니다. 따라서 신뢰 수준은 동일합니다.Worker
클래스를 포함하는 애플리케이션에 여러 어셈블리가 있는 경우 모든 어셈블리가 동일한 신뢰 수준에 있기 때문에 해당 어셈블리 중 하나에 대해 동일한 프로세스가 성공합니다.AccessPrivateMethod
메서드의 두 번째 오버로드가 실행되며, JIT 가시성 검사가 다시 건너뜁니다. 이번에는 동적 메서드가 컴파일될 때 실패합니다. String 클래스의internal
FirstChar
속성에 액세스하려고 하기 때문입니다. String 클래스를 포함하는 어셈블리는 완전히 신뢰할 수 있습니다. 따라서 코드를 내보내는 어셈블리보다 신뢰 수준이 더 높습니다.
이 비교는 ReflectionPermissionFlag.RestrictedMemberAccess 부분적으로 신뢰할 수 있는 코드가 신뢰할 수 있는 코드의 보안을 손상시키지 않고 부분적으로 신뢰할 수 있는 다른 코드에 대한 가시성 검사를 건너뛸 수 있게 하는 방법을 보여 줍니다.
코드
using System;
using System.Reflection.Emit;
using System.Reflection;
using System.Security;
using System.Security.Permissions;
using System.Security.Policy;
using System.Collections;
using System.Diagnostics;
// This code example works properly only if it is run from a fully
// trusted location, such as your local computer.
// Delegates used to execute the dynamic methods.
//
public delegate void Test(Worker w);
public delegate void Test1();
public delegate char Test2(String instance);
// The Worker class must inherit MarshalByRefObject so that its public
// methods can be invoked across application domain boundaries.
//
public class Worker : MarshalByRefObject
{
private void PrivateMethod()
{
Console.WriteLine("Worker.PrivateMethod()");
}
public void SimpleEmitDemo()
{
DynamicMethod meth = new DynamicMethod("", null, null);
ILGenerator il = meth.GetILGenerator();
il.EmitWriteLine("Hello, World!");
il.Emit(OpCodes.Ret);
Test1 t1 = (Test1) meth.CreateDelegate(typeof(Test1));
t1();
}
// This overload of AccessPrivateMethod emits a dynamic method and
// specifies whether to skip JIT visiblity checks. It creates a
// delegate for the method and invokes the delegate. The dynamic
// method calls a private method of the Worker class.
public void AccessPrivateMethod(bool restrictedSkipVisibility)
{
// Create an unnamed dynamic method that has no return type,
// takes one parameter of type Worker, and optionally skips JIT
// visiblity checks.
DynamicMethod meth = new DynamicMethod(
"",
null,
new Type[] { typeof(Worker) },
restrictedSkipVisibility);
// Get a MethodInfo for the private method.
MethodInfo pvtMeth = typeof(Worker).GetMethod("PrivateMethod",
BindingFlags.NonPublic | BindingFlags.Instance);
// Get an ILGenerator and emit a body for the dynamic method.
ILGenerator il = meth.GetILGenerator();
// Load the first argument, which is the target instance, onto the
// execution stack, call the private method, and return.
il.Emit(OpCodes.Ldarg_0);
il.EmitCall(OpCodes.Call, pvtMeth, null);
il.Emit(OpCodes.Ret);
// Create a delegate that represents the dynamic method, and
// invoke it.
try
{
Test t = (Test) meth.CreateDelegate(typeof(Test));
try
{
t(this);
}
catch (Exception ex)
{
Console.WriteLine($"{ex.GetType().Name} was thrown when the delegate was invoked.");
}
}
catch (Exception ex)
{
Console.WriteLine($"{ex.GetType().Name} was thrown when the delegate was compiled.");
}
}
// This overload of AccessPrivateMethod emits a dynamic method that takes
// a string and returns the first character, using a private field of the
// String class. The dynamic method skips JIT visiblity checks.
public void AccessPrivateMethod()
{
DynamicMethod meth = new DynamicMethod("",
typeof(char),
new Type[] { typeof(String) },
true);
// Get a MethodInfo for the 'get' accessor of the private property.
PropertyInfo pi = typeof(System.String).GetProperty(
"FirstChar",
BindingFlags.NonPublic | BindingFlags.Instance);
MethodInfo pvtMeth = pi.GetGetMethod(true);
// Get an ILGenerator and emit a body for the dynamic method.
ILGenerator il = meth.GetILGenerator();
// Load the first argument, which is the target string, onto the
// execution stack, call the 'get' accessor to put the result onto
// the execution stack, and return.
il.Emit(OpCodes.Ldarg_0);
il.EmitCall(OpCodes.Call, pvtMeth, null);
il.Emit(OpCodes.Ret);
// Create a delegate that represents the dynamic method, and
// invoke it.
try
{
Test2 t = (Test2) meth.CreateDelegate(typeof(Test2));
char first = t("Hello, World!");
Console.WriteLine($"{first} is the first character.");
}
catch (Exception ex)
{
Console.WriteLine($"{ex.GetType().Name} was thrown when the delegate was compiled.");
}
}
// The entry point for the code example.
static void Main()
{
// Get the display name of the executing assembly, to use when
// creating objects to run code in application domains.
String asmName = typeof(Worker).Assembly.FullName;
// Create the permission set to grant to other assemblies. In this
// case they are the permissions found in the Internet zone.
Evidence ev = new Evidence();
ev.AddHostEvidence(new Zone(SecurityZone.Internet));
PermissionSet pset = new NamedPermissionSet("Internet", SecurityManager.GetStandardSandbox(ev));
// For simplicity, set up the application domain to use the
// current path as the application folder, so the same executable
// can be used in both trusted and untrusted scenarios. Normally
// you would not do this with real untrusted code.
AppDomainSetup adSetup = new AppDomainSetup();
adSetup.ApplicationBase = ".";
// Create an application domain in which all code that executes is
// granted the permissions of an application run from the Internet.
AppDomain ad = AppDomain.CreateDomain("Sandbox", ev, adSetup, pset, null);
// Create an instance of the Worker class in the partially trusted
// domain. Note: If you build this code example in Visual Studio,
// you must change the name of the class to include the default
// namespace, which is the project name. For example, if the project
// is "AnonymouslyHosted", the class is "AnonymouslyHosted.Worker".
Worker w = (Worker) ad.CreateInstanceAndUnwrap(asmName, "Worker");
// Emit a simple dynamic method that prints "Hello, World!"
w.SimpleEmitDemo();
// Emit and invoke a dynamic method that calls a private method
// of Worker, with JIT visibility checks enforced. The call fails
// when the delegate is invoked.
w.AccessPrivateMethod(false);
// Emit and invoke a dynamic method that calls a private method
// of Worker, skipping JIT visibility checks. The call fails when
// the method is invoked.
w.AccessPrivateMethod(true);
// Unload the application domain. Add RestrictedMemberAccess to the
// grant set, and use it to create an application domain in which
// partially trusted code can call private members, as long as the
// trust level of those members is equal to or lower than the trust
// level of the partially trusted code.
AppDomain.Unload(ad);
pset.SetPermission(
new ReflectionPermission(
ReflectionPermissionFlag.RestrictedMemberAccess));
ad = AppDomain.CreateDomain("Sandbox2", ev, adSetup, pset, null);
// Create an instance of the Worker class in the partially trusted
// domain.
w = (Worker) ad.CreateInstanceAndUnwrap(asmName, "Worker");
// Again, emit and invoke a dynamic method that calls a private method
// of Worker, skipping JIT visibility checks. This time compilation
// succeeds because of the grant for RestrictedMemberAccess.
w.AccessPrivateMethod(true);
// Finally, emit and invoke a dynamic method that calls an internal
// method of the String class. The call fails, because the trust level
// of the assembly that contains String is higher than the trust level
// of the assembly that emits the dynamic method.
w.AccessPrivateMethod();
}
}
/* This code example produces the following output:
Hello, World!
MethodAccessException was thrown when the delegate was invoked.
MethodAccessException was thrown when the delegate was invoked.
Worker.PrivateMethod()
MethodAccessException was thrown when the delegate was compiled.
*/
Imports System.Reflection.Emit
Imports System.Reflection
Imports System.Security
Imports System.Security.Permissions
Imports System.Security.Policy
Imports System.Collections
Imports System.Diagnostics
' This code example works properly only if it is run from a fully
' trusted location, such as your local computer.
' Delegates used to execute the dynamic methods.
'
Public Delegate Sub Test(ByVal w As Worker)
Public Delegate Sub Test1()
Public Delegate Function Test2(ByVal instance As String) As Char
' The Worker class must inherit MarshalByRefObject so that its public
' methods can be invoked across application domain boundaries.
'
Public Class Worker
Inherits MarshalByRefObject
Private Sub PrivateMethod()
Console.WriteLine("Worker.PrivateMethod()")
End Sub
Public Sub SimpleEmitDemo()
Dim meth As DynamicMethod = new DynamicMethod("", Nothing, Nothing)
Dim il As ILGenerator = meth.GetILGenerator()
il.EmitWriteLine("Hello, World!")
il.Emit(OpCodes.Ret)
Dim t1 As Test1 = CType(meth.CreateDelegate(GetType(Test1)), Test1)
t1()
End Sub
' This overload of AccessPrivateMethod emits a dynamic method and
' specifies whether to skip JIT visiblity checks. It creates a
' delegate for the method and invokes the delegate. The dynamic
' method calls a private method of the Worker class.
Overloads Public Sub AccessPrivateMethod( _
ByVal restrictedSkipVisibility As Boolean)
' Create an unnamed dynamic method that has no return type,
' takes one parameter of type Worker, and optionally skips JIT
' visiblity checks.
Dim meth As New DynamicMethod("", _
Nothing, _
New Type() {GetType(Worker)}, _
restrictedSkipVisibility)
' Get a MethodInfo for the private method.
Dim pvtMeth As MethodInfo = GetType(Worker).GetMethod( _
"PrivateMethod", _
BindingFlags.NonPublic Or BindingFlags.Instance)
' Get an ILGenerator and emit a body for the dynamic method.
Dim il As ILGenerator = meth.GetILGenerator()
' Load the first argument, which is the target instance, onto the
' execution stack, call the private method, and return.
il.Emit(OpCodes.Ldarg_0)
il.EmitCall(OpCodes.Call, pvtMeth, Nothing)
il.Emit(OpCodes.Ret)
' Create a delegate that represents the dynamic method, and
' invoke it.
Try
Dim t As Test = CType(meth.CreateDelegate(GetType(Test)), Test)
Try
t(Me)
Catch ex As Exception
Console.WriteLine("{0} was thrown when the delegate was invoked.", _
ex.GetType().Name)
End Try
Catch ex As Exception
Console.WriteLine("{0} was thrown when the delegate was compiled.", _
ex.GetType().Name)
End Try
End Sub
' This overload of AccessPrivateMethod emits a dynamic method that takes
' a string and returns the first character, using a private field of the
' String class. The dynamic method skips JIT visiblity checks.
Overloads Public Sub AccessPrivateMethod()
Dim meth As New DynamicMethod("", _
GetType(Char), _
New Type() {GetType(String)}, _
True)
' Get a MethodInfo for the 'get' accessor of the private property.
Dim pi As PropertyInfo = GetType(String).GetProperty( _
"FirstChar", _
BindingFlags.NonPublic Or BindingFlags.Instance)
Dim pvtMeth As MethodInfo = pi.GetGetMethod(True)
' Get an ILGenerator and emit a body for the dynamic method.
Dim il As ILGenerator = meth.GetILGenerator()
' Load the first argument, which is the target string, onto the
' execution stack, call the 'get' accessor to put the result onto
' the execution stack, and return.
il.Emit(OpCodes.Ldarg_0)
il.EmitCall(OpCodes.Call, pvtMeth, Nothing)
il.Emit(OpCodes.Ret)
' Create a delegate that represents the dynamic method, and
' invoke it.
Try
Dim t As Test2 = CType(meth.CreateDelegate(GetType(Test2)), Test2)
Dim first As Char = t("Hello, World!")
Console.WriteLine("{0} is the first character.", first)
Catch ex As Exception
Console.WriteLine("{0} was thrown when the delegate was compiled.", _
ex.GetType().Name)
End Try
End Sub
End Class
Friend Class Example
' The entry point for the code example.
Shared Sub Main()
' Get the display name of the executing assembly, to use when
' creating objects to run code in application domains.
Dim asmName As String = GetType(Worker).Assembly.FullName
' Create the permission set to grant to other assemblies. In this
' case they are the permissions found in the Internet zone.
Dim ev As New Evidence()
ev.AddHostEvidence(new Zone(SecurityZone.Internet))
Dim pset As New NamedPermissionSet("Internet", SecurityManager.GetStandardSandbox(ev))
' For simplicity, set up the application domain to use the
' current path as the application folder, so the same executable
' can be used in both trusted and untrusted scenarios. Normally
' you would not do this with real untrusted code.
Dim adSetup As New AppDomainSetup()
adSetup.ApplicationBase = "."
' Create an application domain in which all code that executes is
' granted the permissions of an application run from the Internet.
Dim ad As AppDomain = AppDomain.CreateDomain("Sandbox", ev, adSetup, pset, Nothing)
' Create an instance of the Worker class in the partially trusted
' domain. Note: If you build this code example in Visual Studio,
' you must change the name of the class to include the default
' namespace, which is the project name. For example, if the project
' is "AnonymouslyHosted", the class is "AnonymouslyHosted.Worker".
Dim w As Worker = _
CType(ad.CreateInstanceAndUnwrap(asmName, "Worker"), Worker)
' Emit a simple dynamic method that prints "Hello, World!"
w.SimpleEmitDemo()
' Emit and invoke a dynamic method that calls a private method
' of Worker, with JIT visibility checks enforced. The call fails
' when the delegate is invoked.
w.AccessPrivateMethod(False)
' Emit and invoke a dynamic method that calls a private method
' of Worker, skipping JIT visibility checks. The call fails when
' the method is compiled.
w.AccessPrivateMethod(True)
' Unload the application domain. Add RestrictedMemberAccess to the
' grant set, and use it to create an application domain in which
' partially trusted code can call private members, as long as the
' trust level of those members is equal to or lower than the trust
' level of the partially trusted code.
AppDomain.Unload(ad)
pset.SetPermission( _
New ReflectionPermission( _
ReflectionPermissionFlag.RestrictedMemberAccess))
ad = AppDomain.CreateDomain("Sandbox2", ev, adSetup, pset, Nothing)
' Create an instance of the Worker class in the partially trusted
' domain.
w = CType(ad.CreateInstanceAndUnwrap(asmName, "Worker"), Worker)
' Again, emit and invoke a dynamic method that calls a private method
' of Worker, skipping JIT visibility checks. This time compilation
' succeeds because of the grant for RestrictedMemberAccess.
w.AccessPrivateMethod(True)
' Finally, emit and invoke a dynamic method that calls an internal
' method of the String class. The call fails, because the trust level
' of the assembly that contains String is higher than the trust level
' of the assembly that emits the dynamic method.
w.AccessPrivateMethod()
End Sub
End Class
' This code example produces the following output:
'
'Hello, World!
'MethodAccessException was thrown when the delegate was invoked.
'MethodAccessException was thrown when the delegate was invoked.
'Worker.PrivateMethod()
'MethodAccessException was thrown when the delegate was compiled.
'
코드 컴파일
- Visual Studio에서 이 코드 예제를 빌드하는 경우 CreateInstanceAndUnwrap 메서드에 전달할 때 네임스페이스를 포함하도록 클래스의 이름을 변경해야 합니다. 기본적으로 네임스페이스는 프로젝트의 이름입니다. 예를 들어 프로젝트가 "PartialTrust"인 경우 클래스 이름은 "PartialTrust.Worker"여야 합니다.
참고하십시오
.NET