背景:Noda Time包含许多

我们最近收到了issue report件野田的 时间2.x failing within .NET Fiddle.使用Noda的相同代码 Time 1.x工作正常.抛出的异常如下:

覆盖成员时违反继承安全规则: ‘NodaTime.Duration.System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo, System.Runtime.Serialization.StreamingContext)‘.安全性 重写方法的可访问性必须与安全性匹配 被重写的方法的可访问性.

我已经把范围缩小到目标框架:1.十、

我已经设法在当地的一个项目中重现了这一点,但我还没有

在VS2017中复制的步骤:

  • 创建新的解决方案
  • 创建一个新的classic Windows控制台应用程序.网
  • 在"项目属性"中,转到"签名"并使用对程序集进行签名
  • 粘贴以下代码以替换Program.cs.这是一个 this Microsoft sample中代码的缩写版本. 我把所有的路都保持不变,所以如果你想回到 Fuller代码,您应该不需要更改任何其他内容.

代码:

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

注释掉的属性显示了我try 过的东西:

  • SecurityPermission由两篇不同的MS文章(firstsecond),尽管 有趣的是,它们围绕显式/隐式接口实现做不同的事情
  • SecurityCritical是野田佳彦目前拥有的,也是this question's answer的建议
  • 代码分析规则消息有点建议使用SecuritySafeCritical
  • 如果没有any个属性,代码分析规则是满意的——有SecurityPermission个或SecurityCritical
  • 野田佳彦的时间有AllowPartiallyTrustedCallers个;这里的示例在应用或不应用属性的情况下都不起作用.

如果我向UntrustedCode程序集添加[assembly: SecurityRules(SecurityRuleSet.Level1)](并取消对AllowPartiallyTrustedCallers属性的注释),代码将毫无例外地运行,但我认为这是一个糟糕的解决方案,可能会妨碍其他代码.

我完全承认,在这种情况下,我很迷茫

(虽然我的目标是.NET 4.5,但我相信是.NET 4.0安全策略的更改导致了这个问题,因此才有了标签.)

推荐答案

根据the MSDN的说法,在.NET4.0中,对于部分信任的代码,基本上不应该使用ISerializable,而应该使用ISafeSerializationData

引述自https://docs.microsoft.com/en-us/dotnet/standard/serialization/custom-serialization

重要信息

在之前的版本中.NET Framework 4.0中,部分受信任程序集中自定义用户数据的序列化是使用GetObjectData完成的.从版本4.0开始,该方法被标记为SecurityCriticalAttribute属性,该属性阻止在部分受信任的程序集中执行.要解决此问题,请实现ISafeSerializationData接口.

所以,如果你需要的话,可能不是你想听到的,但我认为在继续使用ISerializable的情况下,没有办法解决这个问题(除了回到Level1安全,你说你不想).

PS:ISafeSerializationData个文档声明这只是为了例外,但它似乎没有那么具体,你可能想试一试...我基本上不能用你的示例代码测试它(除了删除ISerializable个工作,但你已经知道了)...你得看看ISafeSerializationData个是否适合你.

PS2:SecurityCritical属性不起作用,因为当以部分信任模式加载程序集时,它会被忽略(on Level2 security).您可以在示例代码中看到它,如果您在调用它之前调试ExecuteUntrustedCode中的target变量,即使您用SecurityCritical属性标记该方法,它也会有IsSecurityTransparenttrueIsSecurityCriticalfalse)

.net相关问答推荐

Powershell机器令牌组

从窗体中移除另一个控件中引用的控件时获取设计时通知

无法在 Blazor Server 应用程序中触发 InputRadio 的 onchange 事件

无法通过构建目标访问 dotnet 的环境变量

图像 UriSource 和数据绑定

Gacutil.exe 成功添加程序集,但在资源管理器中无法查看程序集.为什么?

C# - 获取不包括隐藏文件的文件列表

Int32.ToString() 是特定于文化的吗?

异步总是 WaitingForActivation

多个等待与 Task.WaitAll - 等效?

msbuild,定义条件编译符号

找不到 Assert.Fail 和 Assert.Pass 或等效项

哪个更快:清除集合或实例化新的

System.String.Copy 在 .NET 中有什么用?

寻找 .NET 的命令行参数解析器

如何保护我的 .NET 程序集免受反编译?

设置 System.Drawing.Color 值

在 .NET 中获取默认打印机的最佳方法是什么

如何获取命名空间中的所有类?

如何为我的 C# 应用程序创建产品密钥?