Bau*_*aud 9 .net c# serialization .net-assembly
我将我的类的一个实例序列化为一个文件(带有BinaryFormatter)
之后,在另一个项目中,我想反序列化这个文件,但没有成功,因为我的新项目没有我旧类的描述。在.Deserialize()收到一个异常
Unable to find assembly '*MyAssembly, Version=1.9.0.0, Culture=neutral, PublicKeyToken=null'.*".
Run Code Online (Sandbox Code Playgroud)
但是我有包含我想要反序列化的旧类的描述的程序集的 .DLL。
我不想在项目中添加对 this DLL 的引用(我希望能够反序列化任何类型程序集的类......)
如何通知序列化器/反序列化器使用我动态加载的程序集?
假设您是通过Assembly.Load()或加载程序集Assembly.LoadFrom(),那么正如Chris Shain对动态加载类型的SerializationException 的回答中所述,您可以在反序列化期间使用该事件加载动态程序集。但是,出于安全原因,您将希望防止加载完全意外的程序集。AppDomain.AssemblyResolve
一种可能的实现是引入以下内容:
public class AssemblyResolver
{
readonly string assemblyFullPath;
readonly AssemblyName assemblyName;
public AssemblyResolver(string assemblyName, string assemblyFullPath)
{
// You might want to validate here that assemblyPath really is an absolute not relative path.
// See e.g. /sf/ask/389552061/
this.assemblyFullPath = assemblyFullPath;
this.assemblyName = new AssemblyName(assemblyName);
}
public ResolveEventHandler AssemblyResolve
{
get
{
return (o, a) =>
{
var name = new AssemblyName(a.Name);
if (name.Name == assemblyName.Name) // Check only the name if you want to ignore version. Otherwise you can just check string equality.
return Assembly.LoadFrom(assemblyFullPath);
return null;
};
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后,在启动的某个地方,添加一个合适的ResolveEventHandlerto AppDomain.CurrentDomain.AssemblyResolveeg 如下:
class Program
{
const string assemblyFullPath = @"C:\Full-path-to-my-assembly\MyAssembly.dll";
const string assemblyName = @"MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null";
static Program()
{
AppDomain.CurrentDomain.AssemblyResolve += new AssemblyResolver(assemblyName, assemblyFullPath).AssemblyResolve;
}
Run Code Online (Sandbox Code Playgroud)
这会ResolveEventHandler检查请求的程序集是否具有您的动态程序集的名称,如果是,则从预期的完整路径加载当前版本。
另一种方法是编写自定义SerializationBinder并将其附加到BinaryFormatter.Binder. 在BindToType (string assemblyName, string typeName)绑定器中需要检查属于您的动态程序集的类型,并适当地绑定到它们。这里的技巧是处理动态加载的类型嵌套在来自另一个程序集的泛型中的情况,例如List<MyClass>. 在这种情况下,assemblyName将是List<T>not程序集的名称MyClass。有关如何执行此操作的详细信息,请参阅
在@sgnsajgon询问的评论中 ,我想知道为什么我不能像在项目中显式引用签名程序集时那样反序列化流 - 仅此而已。formatter.Deserialize(stream)
虽然我不知道 Microsoft 员工在设计这些类(回到.Net 1.1 中)时在想什么,但可能是因为:
用 Eric Lippert 的话来说,没有人设计、指定、实施、测试、记录和发布该功能。
BinaryFormatter安全性已经有点像垃圾箱火了,但是Assembly.Load()在BinaryFormatter流中自动调用任何意外的程序集名称可能会使事情变得更糟。
通过“垃圾箱火灾”我的意思是,开箱即用,BinaryFormatter将实例化并填充输入流中指定的类型,这些类型可能不是您期望的类型。因此你可能会这样做
var instance = (MyClass)new BinaryFormatter().Deserialize(stream);
Run Code Online (Sandbox Code Playgroud)
但是,如果流实际上包含诸如此类的序列化攻击小TempFileCollection工具,则将创建并填充该小工具,并且攻击将受到影响。
(关于这种攻击的详细信息,请参阅TypeNameHandling谨慎Newtonsoft的Json,外部JSON因为Json.Net TypeNameHandling汽车的脆弱?, 如何配置Json.NET创建一个漏洞的Web API和阿尔瓦罗·穆尼奥斯与奥列克Mirosh的黑帽纸的https: //www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf . 这些链接指定了如何修改 Json.NET 的配置以启用此类攻击;BinaryFormatter在默认配置中容易受到它们的攻击。)
现在,如果BinaryFormatter自动调用Assembly.Load()无法识别的程序集名称,使用它的应用程序还可能容易受到DLL 植入攻击,其中来自攻击 DLL 的攻击类型会从某个意外位置而不是安全位置意外加载,进一步加剧了攻击风险。
(顺便说一句,如果您选择自己编写,您SerializationBinder可以过滤掉意外类型和/或已知的攻击类型,从而降低攻击小工具注入的风险。这也可能比预期的要困难,因为BinaryFormatter流通常包括序列化的私有或内部类你可能不知道允许。)
顺便说一句,什么是内置的BinaryFormatter基于.NET的序列化的不足之处?对您在使用BinaryFormatter.
二进制序列化对于 DLL Hell 有着严肃的态度。它记录了数据序列化时包含该类型的确切程序集。并坚持在反序列化数据时找到确切的程序集。确保序列化数据与类型匹配的唯一方法是,采取任何捷径只会确保您在幸运时得到异常,而在不幸运时得到垃圾数据。这种情况迟早发生的可能性是 100%。
因此,您需要完全放弃可以使用“动态加载程序集”并让它“反序列化任何类型的类”的想法,这是一种幻觉。您可以旋转命运之轮并<bindingRedirect>在 app.exe.config 文件中添加一个 来强制 CLR 使用不同的程序集版本。处理不幸事件现在是你的责任。许多程序员抓住了这个机会,但很少有人在没有吸取新教训的情况下从经验中回来。必须这样做才能了解后果。所以请继续。
| 归档时间: |
|
| 查看次数: |
1388 次 |
| 最近记录: |