Json.NET反序列化接口属性报无法实例化错误,如何安全解决?
可行的无安全风险解决方案
方案1:单实现场景用自定义JsonConverter固定映射
如果你的ISomething接口只有一个固定的实现类,直接自定义JsonConverter明确指定实现类型即可,完全不需要开启TypeNameHandling,所有实例化逻辑都在你的可控范围内。
自定义Converter代码示例:
public class SomethingConverter : JsonConverter<ISomething> { public override void WriteJson(JsonWriter writer, ISomething value, JsonSerializer serializer) { serializer.Serialize(writer, value); } public override ISomething ReadJson(JsonReader reader, Type objectType, ISomething existingValue, bool hasExistingValue, JsonSerializer serializer) { // 直接指定你要用的具体实现类,比如SomethingImpl return serializer.Deserialize<SomethingImpl>(reader); } }
使用方式有两种:
- 给属性添加
JsonConverter特性:
public class Foo { public int Number { get; set; } [JsonConverter(typeof(SomethingConverter))] public ISomething Thing { get; set; } }
- 全局注册Converter到
JsonSerializerSettings.Converters集合中,适合项目中所有用到ISomething的场景。
方案2:多实现场景用自定义类型标识+白名单控制
如果ISomething有多个不同的实现类需要区分,不要使用.NET自带的类型名作为标识,自己定义业务层面的类型标识,在Converter中只允许白名单内的类型被实例化,完全避免恶意类型注入风险。
Converter代码示例:
public class MultiSomethingConverter : JsonConverter<ISomething> { public override ISomething ReadJson(JsonReader reader, Type objectType, ISomething existingValue, bool hasExistingValue, JsonSerializer serializer) { var jsonObj = JObject.Load(reader); // 读取自定义的类型标识字段 var customType = jsonObj["CustomType"].Value<string>(); ISomething instance = customType switch { "ImplA" => new SomethingImplA(), "ImplB" => new SomethingImplB(), _ => throw new NotSupportedException($"不支持的类型{customType}") }; // 把JSON内容填充到实例中 serializer.Populate(jsonObj.CreateReader(), instance); return instance; } public override void WriteJson(JsonWriter writer, ISomething value, JsonSerializer serializer) { var jsonObj = JObject.FromObject(value, serializer); // 序列化时写入自定义的类型标识 jsonObj.AddFirst(new JProperty("CustomType", value.GetType().Name)); jsonObj.WriteTo(writer); } }
该方案允许反序列化的类型都是你在代码中明确指定的白名单类型,外部输入无法触发任意类型的实例化,没有TypeNameHandling带来的安全风险。
内容的提问来源于stack exchange,提问作者Al Pa chino
相关产品推荐
相关产品推荐

