是否可以使用可信类型标记来防止 Json.Net TypeNameHandling 漏洞?

Is it possible to prevent the Json.Net TypeNameHandling vulnerability with a marker for trusted types?

我正在阅读 vulnerability of deserializing types with Json.Net using a setting different from TypeNameHandling.None. The Json.Net docs recommend implementing a custom SerializationBinder. A simple example of a custom binder that checks types against a list of known types is given here

虽然此解决方案确实有效,但已知类型集在我的场景中并不固定,因为应用程序必须支持扩展,这可能会定义自己的数据 类。一种解决方案是在注册扩展期间扩展已知类型列表,但是,我想到了第二种方法,我想验证一下:

我想为可信类型定义一个通用接口:

(dbc 建议:可以使用自定义属性代替标记界面。)

public interface ITrustedType { }

然后,任何需要由应用程序或扩展序列化(反)序列化的类型都可以实现此接口:

public class Car : ITrustedType
{
   public IList<Passenger> Passengers { get; set; }
   // ...
}

public class Passenger : ITrustedType
{
   // ...
}

自定义绑定器不检查类型列表,而是确保每个(反)序列化类型都实现了受信任的类型接口,如果实现则应用默认行为,如果失败则应用默认行为它没有。

在可枚举类型的情况下,它将确保泛型类型参数是受信任的类型。

到目前为止,这是我测试过的一个简单实现:

public class TrustedTypesBinder : DefaultSerializationBinder
{
    static bool IsCollectionType(Type type)
    {
        return type.GetInterfaces().Any(s => s.Namespace == "System.Collections.Generic" && s.Name.StartsWith("IEnumerable`"));
    }

    static public bool IsTrustedType(Type type)
    {
        if (IsCollectionType(type))
        {
            return type.GenericTypeArguments.All(t => IsTrustedType(t));
        }
        return typeof(ITrustedType).IsAssignableFrom(type);
    }

    public override Type BindToType(string assemblyName, string typeName)
    {
        Type type = base.BindToType(assemblyName, typeName);
        if (!IsTrustedType(type))
            throw new JsonSerializationException(typeName + " is not a trusted type.");
        return type;
    }

    public override void BindToName(Type serializedType, out string assemblyName, out string typeName)
    {
        if (!IsTrustedType(serializedType))
            throw new JsonSerializationException(serializedType.FullName + " is not a trusted type.");
        base.BindToName(serializedType, out assemblyName, out typeName);
    }
}

我怀疑此解决方案是安全的,因为来自应用程序或扩展程序集外部的任何类型都不会实现此接口,因此无法从恶意 JSON 输入构造攻击工具。

我是否遗漏了任何攻击向量?您知道可能会受到危害的方式吗?

编辑: 我知道,任何人都可以实现这个 ITrustedType 接口并赋予它一些任意行为。据我所知,这在运行时的(反)序列化上下文中不应该是相关的。应用程序本身以及扩展都来自可信来源,因此,实现的类型当然是受控的,攻击者不可能将任何新类型添加到已发布的应用程序二进制文件中。

这个问题专门针对在运行时出现的实例化类型,这些类型可能会被用于恶意目的。

编辑 2: 根据 Ben Voigts 的建议,将 ICollection 更改为 IEnumerable。

当你遇到一个没有标记的类型时,检查它的泛型类型参数是不够的,你需要检查每个 public 属性 的类型和每个参数的类型public 构造函数,因为这些是序列化足迹。

例如,您确实不想允许对 System.Data.TypedTableBase<T> 进行反序列化,即使 T 是安全的,因为它具有允许配置数据库访问的 public 属性。