如何在不违反继承安全规则的情况下在.NET 4+中实现ISerializable?

乔恩·斯基特(Jon Skeet):

背景: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:
调用的目标引发了异常。
--->
System.TypeLoadException:
重写成员时违反了继承安全规则:
'UntrustedCode.CustomStruct.System.Runtime.Serialization.ISerializable.GetObjectData(...)。
覆盖方法的安全
可访问性必须与被覆盖方法的安全可访问性相匹配

注释掉的属性显示了我尝试过的事情:

  • SecurityPermissionMS推荐了两篇不同的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安全策略更改,因此引起了该标签。)

Jcl:

根据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调用前正确的,它必须IsSecurityTransparenttrueIsSecurityCriticalfalse即使你用标记的方法SecurityCritical属性)

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何在不使用外部服务的情况下在ASP.NET中获取客户端的外部IPv4地址?

如何在ASP.NET MVC中捆绑资产以在不访问Razor的情况下在Angular中使用?

如何在不访问MVC应用程序中的安全页面的情况下触发IdentityServer4登录?

如何在C#中实现log4net,log4net需要什么?

ADO.Net-如何在不知道架构的情况下在表中插入数据

如何在没有behidcode的情况下在asp.net中隐藏图像

如何在不使用JQuery函数的情况下在angular 4中进行深度复制?

如何在不使用实体框架的情况下在MVC4中执行编辑功能?

如何在不包括年份的情况下在 Swift 4 中显示日期?

如何在不违反C ++中的DRY原理的情况下实现可移动重载?

如何在不继承NgbDatepickerI18n的情况下在Angular中为NgbDatepicker进行翻译?

如何在ASP.NET Core中实现Angle 4服务器预渲染

如何在不编写代码的情况下在Amazon sqs中实现指数补偿

如何在不导入任何库的情况下在 python 中实现单词到 PDF 的转换?

如何在不创建存储过程的情况下在oracle中实现以下目标?

如何在违反唯一约束的情况下在Postgres中返回原始行

如何在不获得循环依赖的情况下使用环回 4 实现链式模型

如何在不使用数据库的情况下在VB.NET的DataGridView中显示数组?

我如何在没有临时文件的情况下在vb.net中执行python?

如何在不使用脚手架技术的情况下在mvc4中创建网格视图

如何在没有bootstrap-vue的情况下在vue.js 2中使用bootstrap 4?

我如何在没有UI的情况下在UE4中生成景观?(按代码)

如何在不提供节点ID的情况下在neo4j中快速创建节点?

如何在没有验证规则的情况下在Yii2中创建方案?

如何在不创建两个类的情况下在MySQL中实现对偶关系(Null,Not Null)?

sql-o如何在不创建存储过程的情况下在oracle中实现以下目标?

在ASP.NET MVC中实现Google Analytics(分析)4

如何在不违反约束的情况下增加主键列中的现有值?

C#ASP.Net:如何在不使用WSDL或代理类的情况下在.NET 4.0 C#中调用Web服务