繁体   English   中英

WCF 类型序列化问题

[英]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);
}

笔记:

  1. 反序列化通过线路提供的类型会使您的应用程序容易受到攻击小工具反序列化攻击,在这种攻击中,攻击者会诱使您的应用程序构建一个在构建、反序列化或处置时影响攻击的类型。 这是 Json.NET 的TypeNameHandling的一个已知漏洞。 详情见:

    如果您的应用曾经构造过RefEntityType的实例,您的应用可能会容易受到此类攻击。 为防止这种情况,您可以根据允许类型的白名单检查反序列化类型。

  2. 在您的问题中,您问为什么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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM