[英]Issue with WCF type serialization
我正面临 WCF 序列化的一个奇怪问题。 我的项目有一个名为RefEntity
的类型,它具有另一个名为RefDomain
的类型的属性。 WCF 服务定义了两种方法,一种将RefEntity
类型作为参数,另一种将RefDomain
类型作为参数。
带有RefDomain
参数的方法似乎没有序列化对象,因为所有属性在服务端都具有null
值。 然而,带有RefEntity
参数(和RefDomain
作为成员)的方法按预期工作( RefDomain
成员按预期序列化)。
我在这里错过了什么?
public class RefDomain
{
private string name;
private RefDomain parent;
private Type entityType;
public string Name
{
get => this.name;
protected set => this.name = value;
}
public RefDomain Parent
{
get => this.parent;
protected set => this.parent = value;
}
public Type RefEntityType
{
get => this.entityType;
protected set => this.entityType = value;
}
}
您的属性具有受保护的 setter,并且DataContractSerializer
只会序列化完全公开的属性,除非标有数据协定属性。
应用必要的[DataContract]
和[DataMember]
属性后,您会发现第二个问题,即DataContractSerializer
无法序列化System.Type
类型的值。 (演示小提琴 #1在这里)。 要序列化您的Type RefEntityType
属性,您需要对可序列化的Type
使用某种代理项,例如字符串。
因此,可以通过数据协定序列化程序序列化以下版本的RefDomain
:
public class RefDomain
{
private string name;
private RefDomain parent;
private Type entityType;
[DataMember]
public string Name
{
get => this.name;
protected set => this.name = value;
}
[DataMember]
public RefDomain Parent
{
get => this.parent;
protected set => this.parent = value;
}
public Type RefEntityType
{
get => this.entityType;
protected set => this.entityType = value;
}
[DataMember(Name = "RefEntityType")]
string RefEntityTypeString
{
get
{
return RefEntityType?.FullName;
}
set
{
// Note that simply deserializing a type supplied over the wire will make your application vulnerable to type injection attacks,
// in which an attacker tricks you into constructing a type that effects an attack when constructed, deserialized or disposed.
// This is a known vulnerability with Json.NET's TypeNameHandling.None. See for details
// https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf
// https://stackoverflow.com/questions/39565954/typenamehandling-caution-in-newtonsoft-json/
// https://stackoverflow.com/questions/49038055/external-json-vulnerable-because-of-json-net-typenamehandling-auto
var type = value == null ? null : Type.GetType(value);
// Check the type against a whitelist here?
RefEntityType = type;
}
}
// Your class was had no way to set the protected properties, so I added a parameterized constructor.
public RefDomain() { }
public RefDomain(string name, RefDomain parent, Type entityType) => (this.name, this.parent, this.entityType) = (name, parent, entityType);
}
笔记:
反序列化通过线路提供的类型会使您的应用程序容易受到攻击小工具反序列化攻击,在这种攻击中,攻击者会诱使您的应用程序构建一个在构建、反序列化或处置时影响攻击的类型。 这是 Json.NET 的TypeNameHandling
的一个已知漏洞。 详情见:
如果您的应用曾经构造过RefEntityType
的实例,您的应用可能会容易受到此类攻击。 为防止这种情况,您可以根据允许类型的白名单检查反序列化类型。
在您的问题中,您问为什么RefDomain
的部分公共属性在序列化为某个其他根对象RefEntity
的成员时被序列化。 您的问题中没有足够的信息来解释为什么会这样。 也许RefEntity
被序列化的端点正在使用具有子类RefDomain
的端点,或使用序列化代理项,或已设置DataContractSerializerSettings.SerializeReadOnlyTypes = true
。
但是不管为什么部分公共属性RefDomain
属性在RefEntity
内部被序列化,如果您希望在所有上下文中序列化这些属性,用[DataContract]
标记RefDomain
并用[DataMember]
标记属性是正确且足够的
演示小提琴 #2在这里。
据我所知,wcf中使用的自定义类型需要用Data Contract属性来标记,成员需要用Data Member属性来标记。
您可以将 RefDomain 标记为数据协定属性,或者创建一个单独的类来保存来自 RefDomain 的数据并通过 wcf 传递它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.