背景: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中重现的步骤:
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);
}
}
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:
调用的目标引发了异常。
--->
System.TypeLoadException:
重写成员时违反了继承安全规则:
'UntrustedCode.CustomStruct.System.Runtime.Serialization.ISerializable.GetObjectData(...)。
覆盖方法的安全
可访问性必须与被覆盖方法的安全可访问性相匹配。
注释掉的属性显示了我尝试过的事情:
SecurityPermission
MS推荐了两篇不同的MS文章(第一篇,第二篇),尽管有趣的是,它们围绕显式/隐式接口实现做了不同的事情SecurityCritical
是Noda Time当前拥有的,并且这个问题的答案表明SecuritySafeCritical
由代码分析规则消息建议SecurityPermission
还是SecurityCritical
存在,规则都会告诉您删除属性-除非您确实有AllowPartiallyTrustedCallers
。在两种情况下遵循建议均无济于事。AllowPartiallyTrustedCallers
应用;无论是否应用属性,此处的示例均不起作用。如果我将其添加[assembly: SecurityRules(SecurityRuleSet.Level1)]
到UntrustedCode
程序集中(并取消注释该AllowPartiallyTrustedCallers
属性),则代码会无例外地运行,但是我认为这是一个很糟糕的解决方案,可以阻止其他代码。
我完全承认,在涉及.NET的这种安全方面时,我已经迷失了。那么什么可以做些什么来面向.NET 4.5,但让我的类型来实现ISerializable
,并在环境,如.NET小提琴仍然可以使用?
(虽然我的目标是.NET 4.5,但我认为是导致问题的原因是.NET 4.0安全策略更改,因此引起了该标签。)
根据MSDN,在.NET 4.0中,基本上您不应使用ISerializable
部分受信任的代码,而应使用ISafeSerializationData
从https://docs.microsoft.com/zh-cn/dotnet/standard/serialization/custom-serialization引用
重要
在.NET Framework 4.0之前的版本中,使用GetObjectData完成了部分受信任程序集中的自定义用户数据的序列化。从4.0版开始,该方法带有SecurityCriticalAttribute属性标记,该属性阻止在部分受信任的程序集中执行。要变通解决此问题,实现ISafeSerializationData接口。
因此,如果您需要它,可能不是您想听的,但是我认为在ISerializable
继续使用时,它周围没有任何办法(除了回到Level1
您说不想的安全性之外)。
PS:ISafeSerializationData
文档指出这只是为了例外,但似乎并没有那么具体,您可能需要试一下...我基本上无法使用示例代码对其进行测试(除了删除ISerializable
作品,但您已经知道了)...您必须查看是否ISafeSerializationData
足够适合您。
PS2:该SecurityCritical
属性不起作用,因为在以部分信任模式(在Level2安全性上)加载程序集时,将忽略该属性。你可以看到它在你的示例代码,如果调试target
变量ExecuteUntrustedCode
调用前正确的,它必须IsSecurityTransparent
要true
和IsSecurityCritical
来false
即使你用标记的方法SecurityCritical
属性)
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句