배경 : Noda Time 에는 직렬화 가능한 구조체가 많이 포함되어 있습니다. 이진 직렬화를 싫어하지만 1.x 타임 라인에서 지원해 달라는 많은 요청을 받았습니다. ISerializable
인터페이스 를 구현하여 지원합니다 .
.NET Fiddle 내에서 실패 하는 Noda Time 2.x의 최근 문제 보고서 를 받았습니다 . Noda Time 1.x를 사용하는 동일한 코드가 정상적으로 작동합니다. 던져진 예외는 다음과 같습니다.
멤버를 재정의하는 동안 상속 보안 규칙이 위반되었습니다 : 'NodaTime.Duration.System.Runtime.Serialization.ISerializable.GetObjectData (System.Runtime.Serialization.SerializationInfo, System.Runtime.Serialization.StreamingContext)'. 재정의하는 메서드의 보안 접근성은 재정의되는 메서드의 보안 접근성과 일치해야합니다.
대상 프레임 워크로 범위를 좁혔습니다. 1.x는 .NET 3.5 (클라이언트 프로필)를 대상으로합니다. 2.x는 .NET 4.5를 대상으로합니다. 지원 PCL 대 .NET Core 및 프로젝트 파일 구조 측면에서 큰 차이가 있지만 이것은 관련이없는 것처럼 보입니다.
나는 이것을 로컬 프로젝트에서 재현했지만 해결책을 찾지 못했습니다.
VS2017에서 재현하는 단계 :
- 새로운 솔루션 만들기
- .NET 4.5.1을 대상으로하는 새로운 클래식 Windows 콘솔 응용 프로그램을 만듭니다. 나는 그것을 "CodeRunner"라고 불렀다.
- 프로젝트 속성에서 서명으로 이동하고 새 키로 어셈블리에 서명합니다. 암호 요구 사항을 확인하고 키 파일 이름을 사용하십시오.
- 다음 코드를 붙여 넣어
Program.cs
. 이것은 이 Microsoft 샘플 에있는 코드의 축약 된 버전입니다 . 모든 경로를 동일하게 유지 했으므로 더 완전한 코드로 돌아가고 싶다면 다른 것을 변경할 필요가 없습니다.
암호:
using System;
using System.Security;
using System.Security.Permissions;
class Sandboxer : MarshalByRefObject
{
static void Main()
{
var adSetup = new AppDomainSetup();
adSetup.ApplicationBase = System.IO.Path.GetFullPath(@"..\..\..\UntrustedCode\bin\Debug");
var permSet = new PermissionSet(PermissionState.None);
permSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
var fullTrustAssembly = typeof(Sandboxer).Assembly.Evidence.GetHostEvidence<System.Security.Policy.StrongName>();
var newDomain = AppDomain.CreateDomain("Sandbox", null, adSetup, permSet, fullTrustAssembly);
var handle = Activator.CreateInstanceFrom(
newDomain, typeof(Sandboxer).Assembly.ManifestModule.FullyQualifiedName,
typeof(Sandboxer).FullName
);
Sandboxer newDomainInstance = (Sandboxer) handle.Unwrap();
newDomainInstance.ExecuteUntrustedCode("UntrustedCode", "UntrustedCode.UntrustedClass", "IsFibonacci", new object[] { 45 });
}
public void ExecuteUntrustedCode(string assemblyName, string typeName, string entryPoint, Object[] parameters)
{
var target = System.Reflection.Assembly.Load(assemblyName).GetType(typeName).GetMethod(entryPoint);
target.Invoke(null, parameters);
}
}
- "UntrustedCode"라는 다른 프로젝트를 만듭니다. 이것은 클래식 데스크탑 클래스 라이브러리 프로젝트 여야합니다.
- 어셈블리에 서명하십시오. 새 키를 사용하거나 CodeRunner와 동일한 키를 사용할 수 있습니다. (이것은 부분적으로 Noda Time 상황을 모방하고 부분적으로 코드 분석을 행복하게 유지하기위한 것입니다.)
- 다음 코드를 붙여 넣으십시오
Class1.cs
(있는 내용 덮어 쓰기).
암호:
using System;
using System.Runtime.Serialization;
using System.Security;
using System.Security.Permissions;
// [assembly: AllowPartiallyTrustedCallers]
namespace UntrustedCode
{
public class UntrustedClass
{
// Method named oddly (given the content) in order to allow MSDN
// sample to run unchanged.
public static bool IsFibonacci(int number)
{
Console.WriteLine(new CustomStruct());
return true;
}
}
[Serializable]
public struct CustomStruct : ISerializable
{
private CustomStruct(SerializationInfo info, StreamingContext context) { }
//[SecuritySafeCritical]
//[SecurityCritical]
//[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
throw new NotImplementedException();
}
}
}
CodeRunner 프로젝트를 실행하면 다음 예외가 발생합니다 (가독성을 위해 형식이 변경됨).
처리되지 않은 예외 : System.Reflection.TargetInvocationException :
호출 대상에서 예외가 throw되었습니다.
--->
System.TypeLoadException :
멤버를 재정의하는 동안 상속 보안 규칙 위반 :
'UntrustedCode.CustomStruct.System.Runtime.Serialization.ISerializable.GetObjectData (...).
재정의하는 메서드의 보안 접근성은 재정의되는 메서드의 보안
접근성 과 일치해야합니다 .
주석 처리 된 속성은 내가 시도한 것을 보여줍니다.
SecurityPermission
흥미롭게도 명시 적 / 암시 적 인터페이스 구현에 대해 서로 다른 작업을 수행하지만 두 개의 서로 다른 MS 기사 ( 첫 번째 , 두 번째 )에서 권장합니다.SecurityCritical
Noda Time이 현재 가지고있는 것이며, 이 질문의 답변이 제안하는 것입니다.SecuritySafeCritical
코드 분석 규칙 메시지에서 다소 제안됩니다.- 없이 어떤 속성 코드 분석 규칙은 행복하다 - 하나와 함께
SecurityPermission
또는SecurityCritical
현재, 규칙 속성을 제거하는 당신에게 - 당신이하지 않으면 할 수 있습니다AllowPartiallyTrustedCallers
. 두 경우 모두 제안 사항을 따르는 것은 도움이되지 않습니다. - Noda Time이
AllowPartiallyTrustedCallers
적용되었습니다. 여기의 예는 속성이 적용되거나 적용되지 않고 작동하지 않습니다.
예외없이 코드가 실행 내가 추가 할 경우 [assembly: SecurityRules(SecurityRuleSet.Level1)]
받는 UntrustedCode
조립 (과의 주석 AllowPartiallyTrustedCallers
속성),하지만 난 그 다른 코드를 방해 할 수있는 문제에 대한 빈약 한 솔루션입니다 생각합니다.
.NET의 이런 종류의 보안 측면에 관해서는 꽤 잃어버린 것을 완전히 인정합니다. 그래서 수 있습니다 나는 .NET 4.5을 대상으로 아직 내 유형을 구현할 수 있도록하기 위해 수행 ISerializable
하고 여전히 .NET 바이올린과 같은 환경에서 사용?
(내가 .NET 4.5를 대상으로하고 있지만 문제를 일으킨 것은 .NET 4.0 보안 정책 변경 사항이므로 태그가 있다고 생각합니다.)
AllowPartiallyTrustedCallers
트릭을 할해야하지만, 차이 만들하지 않는 것