You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#(.NET)中Newtonsoft.Json不安全反序列化相关技术问询

问题背景
  • 正在开发对接第三方「万能API(God API)」的接口,该API支持900+功能,接收通用object类型参数
  • 已在仓库首个提交中搭建最小示例(TestRequests.http可用于Rider HTTP客户端或Postman)
  • 虽设置TypeNameHandling.None,公司安全审核仍认为API契约含object类型存在OWASP 2017 A8不安全反序列化风险,要求全部使用严格类型
  • 尝试用抽象基类时,.NET报错:"Could not create an instance of type DeserializationDemo.BaseSetting. Type is an interface or abstract class and cannot be instantiated."
  • 改用自定义ModelBinder可运行,但参数会被反序列化为Newtonsoft.Json.Linq.JObject,且发现DemoContract1也会被转成该类型,担心仍有安全风险
  • 当前仅有的替代方案是为900+功能各创建独立的严格类型端点,希望得到两个问题的解答:
    1. 设置TypeNameHandling.None是否不足以避免不安全反序列化?
    2. 是否有替代Custom ModelBinder的方案,可严格限制允许类型且不会反序列化为JObject?
解答

1. TypeNameHandling.None是否能避免不安全反序列化?

是的,在正常配置下,TypeNameHandling.None足以阻断绝大多数基于类型注入的不安全反序列化攻击。

OWASP A8的不安全反序列化风险核心是:攻击者通过恶意构造的序列化数据,注入带危险逻辑的类实例,让反序列化器创建该对象并执行恶意代码。而TypeNameHandling.None会让Newtonsoft.Json完全忽略序列化数据中的类型信息,仅按你指定的目标类型反序列化——哪怕攻击者在请求里塞了类型注入的payload,反序列化器也不会识别,只会尝试把数据转成目标类型,失败就直接抛出异常。

安全审核的顾虑可能是基于“object类型本身存在不确定性”的通用风险,但从技术实现上,只要你没开启类型自动识别(即TypeNameHandling设为None),且反序列化逻辑中没有动态推断类型,object参数的反序列化不会引入额外的不安全反序列化风险。

2. 替代Custom ModelBinder的方案:泛型+类型约束的强类型端点封装

不需要为900+功能逐个写独立端点,可以用泛型控制器+类型约束的方式,既保证严格类型,又避免重复代码,同时不会反序列化为JObject。

具体实现步骤:

  1. 定义所有功能对应的强类型参数模型,统一实现一个标记接口(或继承同一个非抽象基类):
public interface IApiSetting { }

public class DemoContract1 : IApiSetting
{
    public string Name { get; set; }
    public int Age { get; set; }
}

// 其他900+功能的参数类都实现IApiSetting
  1. 创建泛型控制器,通过泛型参数约束限制允许的类型:
[ApiController]
[Route("api/[controller]")]
public class GodApiController<T> : ControllerBase where T : IApiSetting, new()
{
    private readonly IThirdPartyGodApi _thirdPartyApi;

    public GodApiController(IThirdPartyGodApi thirdPartyApi)
    {
        _thirdPartyApi = thirdPartyApi;
    }

    [HttpPost]
    public async Task<IActionResult> Post([FromBody] T setting)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }
        // 调用第三方API,直接传入强类型的setting
        var result = await _thirdPartyApi.CallAsync(setting);
        return Ok(result);
    }
}
  1. 在Program.cs中通过反射批量注册所有泛型控制器的具体实现:
builder.Services.AddControllers()
    .AddNewtonsoftJson(options =>
    {
        options.SerializerSettings.TypeNameHandling = TypeNameHandling.None;
    });

// 反射获取所有实现IApiSetting的类型,批量注册泛型控制器
var apiSettingTypes = Assembly.GetExecutingAssembly().GetTypes()
    .Where(t => typeof(IApiSetting).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract);

foreach (var type in apiSettingTypes)
{
    var controllerType = typeof(GodApiController<>).MakeGenericType(type);
    builder.Services.AddTransient(controllerType);
}

方案优势

  • 每个功能对应一个强类型控制器实例,但无需手动编写900个控制器,通过反射批量注册即可
  • 反序列化直接针对具体的T类型(如DemoContract1),不会转成JObject,完全符合安全审核的“严格类型”要求
  • 可维护性强,新增功能仅需添加对应的IApiSetting实现类即可

额外适配:第三方API需接收object参数

如果第三方API必须接收object类型,直接把强类型的T实例传入即可——任何强类型对象都可隐式转为object,该转换类型安全,不会引入反序列化风险。


内容的提问来源于stack exchange,提问作者Paul Nogas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 18:06:20