在这个链接上,在备注部分提到了" TypeNameHandling".在什么情况下,如果使用序列化/反序列化来自外部源的JSON会有害SerializationBinder?一个工作的例子将不胜感激.
当我将Json.NET设置为序列化并将TypeNameHandling设置为TypeNameHandling.Auto时,它正确地为对象的子属性设置$ type,但是对于被序列化的根对象没有这样做.为什么?
请考虑以下repro:
public class Animal
{
public Animal[] Offspring { get; set; }
}
public class Dog : Animal {}
Animal fido = new Dog
{
Offspring = new Animal[] { new Dog() }
};
var json = JsonConvert.SerializeObject(fido,
new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto
});
Run Code Online (Sandbox Code Playgroud)
发送到json变量的Json 是:
{
"Offspring": [{
"$type": "MyApp.Dog, MyApp",
"Offspring": null
}]
}
Run Code Online (Sandbox Code Playgroud)
Json.NET 文档说,TypeNameHandling.Auto行为是:
当序列化对象的类型与其声明的类型不同时,请包含.NET类型名称.
我的问题是 - 为什么fido不
"$type": "MyApp.Dog, MyApp",喜欢它的小狗?:)
更新:我从这个问题的接受答案中发现,我可以通过执行以下操作强制添加$ type:
var …Run Code Online (Sandbox Code Playgroud) 反序列化接口和抽象属性的一种方法是通过在序列化和反序列化期间将TypeNameHandling设置为Auto来实现.但是,当我在直接序列化和反序列化接口对象时尝试相同的操作时,它不起作用 -
interface ISample
{
string Key { get; set; }
}
class A : ISample
{
public string Key { get; set; }
public A(string key)
{
this.Key = key;
}
}
class B : ISample
{
public string Key { get; set; }
public B(string key)
{
this.Key = key;
}
}
Run Code Online (Sandbox Code Playgroud)
序列化和反序列化代码 -
ISample a = new A("keyA");
ISample b = new B("keyB");
var settings = new JsonSerializerSettings();
settings.TypeNameHandling = TypeNameHandling.Auto;
var stringA = JsonConvert.SerializeObject(a, settings);
var …Run Code Online (Sandbox Code Playgroud) 给出以下代码段:
using System;
using Newtonsoft.Json;
namespace JsonTestje
{
class Other
{
public string Message2 { get; set; }
}
class Demo
{
public string Message { get; set; }
public Other Other { get; set; }
}
class Program
{
static void Main(string[] args)
{
var demo = new Demo
{
Message = "Hello, World!",
Other = new Other
{
Message2 = "Here be dragons!"
}
};
var settings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto,
Formatting = Formatting.Indented
}; …Run Code Online (Sandbox Code Playgroud) 我使用TypeNameHandling在json中序列化和反序列化派生类的列表.它与属性和属性完美配合JsonProperty
public abstract class Animal
{
public bool CanFly { get; set;}
}
public class FlyingAnimal : Animal
{
public FlyingAnimal() { this.CanFly = true; }
}
public class SwimmingAnimal : Animal
{
public SwimmingAnimal() { this.CanFly = false; }
}
public class World
{
public World() {
this.Animals = new List<Animal>();
this.Animals.Add(new FlyingAnimal());
this.Animals.Add(new SwimmingAnimal());
}
[JsonProperty(ItemTypeNameHandling = TypeNameHandling.Auto)]
public List<Animal> Animals { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
现在,我需要一个返回派生类列表的WebAPI:
[RoutePrefix("Animals")]
public class AnimalsController : ApiController
{
public …Run Code Online (Sandbox Code Playgroud) 在我们的 API 上,我们需要接收 json,将其反序列化为接口,设置一个字段,然后将其发送出去。为了实现这一点,我在两端将 jsonConvert 设置为使用 TypeNameHandling.All。有问题的端点应该被相当锁定,但总有可能有人获得访问权限并使用危险的构造函数或垃圾收集方法将 $type 设置为系统类。
我的问题是在尝试反序列化之前澄清类型的名称空间是否足够安全?或者是否仍然存在 json 中具有危险类类型的子对象之类的风险?如果仍然存在风险或我错过的漏洞,我可以采取哪些其他步骤来减轻危险?
我们的公司名称位于我们使用的每个命名空间的开头,因此在下面的代码中,我们只需检查 json 中设置的类型是否以我们的公司名称开头。开头的 {} 只是让编译器知道在检查后不需要将 JObject 保留在内存中。
{ //check the type is valid
var securityType = JsonConvert.DeserializeObject<JObject>(request.requestJson);
JToken type;
if (securityType.TryGetValue("$type", out type))
{
if (!type.ToString().ToLower().StartsWith("foo")) { //'foo' is our company name, all our namespaces start with foo
await logError($"Possible security violation, client tried to instantiate {type}", clientId: ClientId);
throw new Exception($"Request type {type} not supported, please use an IFoo");
}
}
else
{
throw new Exception("set a …Run Code Online (Sandbox Code Playgroud)