CA2328:确保 JsonSerializerSettings 是安全的

2022-02-20 19:33:30 浏览数 (1)

规则 ID

CA2328

类别

安全性

修复是中断修复还是非中断修复

非中断

原因

如果 Newtonsoft.Json.JsonSerializerSettings 实例的以下两个条件均可为 true,则会触发此规则:

TypeNameHandling 属性是 None 以外的值。

SerializationBinder 属性为 NULL。

必须通过以下其中一种方法来使用 JsonSerializerSettings 实例:

初始化为类字段或属性。

由方法返回。

传递给 JsonSerializer.Create 或 JsonSerializer.CreateDefault。

传递给具有 JsonSerializerSettings 参数的 JsonConvert 方法。

此规则类似于 CA2327,但在这种情况下,分析过程无法明确确定设置是否不安全。

默认情况下,此规则会分析整个代码库,但这是可配置的。

规则说明

反序列化不受信任的数据时,不安全的反序列化程序易受攻击。 攻击者可能会修改序列化数据,使其包含非预期类型,进而注入具有不良副作用的对象。 例如,针对不安全反序列化程序的攻击可以在基础操作系统上执行命令,通过网络进行通信,或删除文件。

此规则会查找 Newtonsoft.Json.JsonSerializerSettings 实例,这些实例可能被配置为对输入中指定的类型执行反序列化,且可能未配置为限制带有 Newtonsoft.Json.Serialization.ISerializationBinder 的反序列化类型。 如果要禁止对完全在输入中指定的类型进行反序列化,请禁用规则 CA2327、CA2328、CA2329 和 CA2330,并启用规则 CA2326。

如何解决冲突

如果可能,请使用 TypeNameHandling 的 None 值。

使序列化的数据免被篡改。 序列化后,对序列化的数据进行加密签名。 在反序列化之前,验证加密签名。 保护加密密钥不被泄露,并针对密钥轮换进行设计。

限制反序列化的类型。 实现自定义 Newtonsoft.Json.Serialization.ISerializationBinder。 在对 Json.NET 执行反序列化前,请确保在 Newtonsoft.Json.JsonSerializerSettings.SerializationBinder 属性中指定自定义 ISerializationBinder。 在已重写的 Newtonsoft.Json.Serialization.ISerializationBinder.BindToType 方法中,如果类型是非预期类型,会返回 null 或引发异常以停止反序列化。

何时禁止显示警告

在以下情况下,禁止显示此规则的警告是安全的:

已知输入为受信任输入。 考虑应用程序的信任边界和数据流可能会随时间发生变化。

你采取了如何修复冲突的某项预防措施。

你知道,当 TypeNameHandling 属性是 None 以外的值时,将始终设置 Newtonsoft.Json.JsonSerializerSettings.SerializationBinder 属性。

配置代码以进行分析

使用下面的选项来配置代码库的哪些部分要运行此规则。

排除特定符号

排除特定类型及其派生类型

你可以仅为此规则、为所有规则或为此类别(安全性)中的所有规则配置这些选项。 有关详细信息,请参阅代码质量规则配置选项。

排除特定符号

可以从分析中排除特定符号,如类型和方法。 例如,若要指定规则不应针对名为 MyType 的类型中的任何代码运行,请将以下键值对添加到项目中的 .editorconfig 文件:

dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType

选项值中允许的符号名称格式(用 | 分隔):

仅符号名称(包括具有相应名称的所有符号,不考虑包含的类型或命名空间)。

完全限定的名称,使用符号的文档 ID 格式。 每个符号名称都需要带有一个符号类型前缀,例如表示方法的 M:、表示类型的 T:,以及表示命名空间的 N:。

.ctor 表示构造函数,.cctor 表示静态构造函数。

示例:

选项值

总结

dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType

匹配名为 MyType 的所有符号。

dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType1|MyType2

匹配名为 MyType1 或 MyType2 的所有符号。

dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS.MyType.MyMethod(ParamType)

匹配带有指定的完全限定签名的特定方法 MyMethod。

dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS1.MyType1.MyMethod1(ParamType)|M:NS2.MyType2.MyMethod2(ParamType)

匹配带有各自的完全限定签名的特定方法 MyMethod1 和 MyMethod2。

排除特定类型及其派生类型

可以从分析中排除特定类型及其派生类型。 例如,若要指定规则不应针对名为 MyType 的类型及其派生类型中的任何代码运行,请将以下键值对添加到项目中的 .editorconfig 文件:

dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType

选项值中允许的符号名称格式(用 | 分隔):

仅类型名称(包括具有相应名称的所有类型,不考虑包含的类型或命名空间)。

完全限定的名称,使用符号的文档 ID 格式,前缀为 T:(可选)。

示例:

选项值

总结

dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType

匹配名为 MyType 的所有类型及其所有派生类型。

dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType1|MyType2

匹配名为 MyType1 或 MyType2 的所有类型及其所有派生类型。

dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS.MyType

匹配带有给定的完全限定名称的特定类型 MyType 及其所有派生类型。

dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS1.MyType1|M:NS2.MyType2

匹配带有各自的完全限定名称的特定类型 MyType1 和 MyType2 及其所有派生类型。

伪代码示例

冲突

using System;

using Newtonsoft.Json;

using Newtonsoft.Json.Serialization;

public class BookRecordSerializationBinder : ISerializationBinder

{

// To maintain backwards compatibility with serialized data before using an ISerializationBinder.

private static readonly DefaultSerializationBinder Binder = new DefaultSerializationBinder();

public void BindToName(Type serializedType, out string assemblyName, out string typeName)

{

Binder.BindToName(serializedType, out assemblyName, out typeName);

}

public Type BindToType(string assemblyName, string typeName)

{

// If the type isn't expected, then stop deserialization.

if (typeName != "BookRecord" && typeName != "AisleLocation" && typeName != "WarehouseLocation")

{

return null;

}

return Binder.BindToType(assemblyName, typeName);

}

}

public class BookRecord

{

public string Title { get; set; }

public object Location { get; set; }

}

public abstract class Location

{

public string StoreId { get; set; }

}

public class AisleLocation : Location

{

public char Aisle { get; set; }

public byte Shelf { get; set; }

}

public class WarehouseLocation : Location

{

public string Bay { get; set; }

public byte Shelf { get; set; }

}

public static class Binders

{

public static ISerializationBinder BookRecord = new BookRecordSerializationBinder();

}

public class ExampleClass

{

public BookRecord DeserializeBookRecord(string s)

{

JsonSerializerSettings settings = new JsonSerializerSettings();

settings.TypeNameHandling = TypeNameHandling.Auto;

settings.SerializationBinder = Binders.BookRecord;

return JsonConvert.DeserializeObject<BookRecord>(s, settings); // CA2328 -- settings might be null

}

}

Imports System

Imports Newtonsoft.Json

Imports Newtonsoft.Json.Serialization

Public Class BookRecordSerializationBinder

Implements ISerializationBinder

' To maintain backwards compatibility with serialized data before using an ISerializationBinder.

Private Shared ReadOnly Property Binder As New DefaultSerializationBinder()

Public Sub BindToName(serializedType As Type, ByRef assemblyName As String, ByRef typeName As String) Implements ISerializationBinder.BindToName

Binder.BindToName(serializedType, assemblyName, typeName)

End Sub

Public Function BindToType(assemblyName As String, typeName As String) As Type Implements ISerializationBinder.BindToType

' If the type isn't expected, then stop deserialization.

If typeName <> "BookRecord" AndAlso typeName <> "AisleLocation" AndAlso typeName <> "WarehouseLocation" Then

Return Nothing

End If

Return Binder.BindToType(assemblyName, typeName)

End Function

End Class

Public Class BookRecord

Public Property Title As String

Public Property Location As Location

End Class

Public MustInherit Class Location

Public Property StoreId As String

End Class

Public Class AisleLocation

Inherits Location

Public Property Aisle As Char

Public Property Shelf As Byte

End Class

Public Class WarehouseLocation

Inherits Location

Public Property Bay As String

Public Property Shelf As Byte

End Class

Public Class Binders

Public Shared Property BookRecord As ISerializationBinder = New BookRecordSerializationBinder()

End Class

Public Class ExampleClass

Public Function DeserializeBookRecord(s As String) As BookRecord

Dim settings As JsonSerializerSettings = New JsonSerializerSettings()

settings.TypeNameHandling = TypeNameHandling.Auto

settings.SerializationBinder = Binders.BookRecord

Return JsonConvert.DeserializeObject(Of BookRecord)(s, settings) ' CA2328 -- settings might be Nothing

End Function

End Class

解决方案

using System;

using Newtonsoft.Json;

using Newtonsoft.Json.Serialization;

public class BookRecordSerializationBinder : ISerializationBinder

{

// To maintain backwards compatibility with serialized data before using an ISerializationBinder.

private static readonly DefaultSerializationBinder Binder = new DefaultSerializationBinder();

public void BindToName(Type serializedType, out string assemblyName, out string typeName)

{

Binder.BindToName(serializedType, out assemblyName, out typeName);

}

public Type BindToType(string assemblyName, string typeName)

{

// If the type isn't expected, then stop deserialization.

if (typeName != "BookRecord" && typeName != "AisleLocation" && typeName != "WarehouseLocation")

{

return null;

}

return Binder.BindToType(assemblyName, typeName);

}

}

public class BookRecord

{

public string Title { get; set; }

public object Location { get; set; }

}

public abstract class Location

{

public string StoreId { get; set; }

}

public class AisleLocation : Location

{

public char Aisle { get; set; }

public byte Shelf { get; set; }

}

public class WarehouseLocation : Location

{

public string Bay { get; set; }

public byte Shelf { get; set; }

}

public static class Binders

{

public static ISerializationBinder BookRecord = new BookRecordSerializationBinder();

}

public class ExampleClass

{

public BookRecord DeserializeBookRecord(string s)

{

JsonSerializerSettings settings = new JsonSerializerSettings();

settings.TypeNameHandling = TypeNameHandling.Auto;

// Ensure that SerializationBinder is non-null before deserializing

settings.SerializationBinder = Binders.BookRecord ?? throw new Exception("Expected non-null");

return JsonConvert.DeserializeObject<BookRecord>(s, settings);

}

}

Imports System

Imports Newtonsoft.Json

Imports Newtonsoft.Json.Serialization

Public Class BookRecordSerializationBinder

Implements ISerializationBinder

' To maintain backwards compatibility with serialized data before using an ISerializationBinder.

Private Shared ReadOnly Property Binder As New DefaultSerializationBinder()

Public Sub BindToName(serializedType As Type, ByRef assemblyName As String, ByRef typeName As String) Implements ISerializationBinder.BindToName

Binder.BindToName(serializedType, assemblyName, typeName)

End Sub

Public Function BindToType(assemblyName As String, typeName As String) As Type Implements ISerializationBinder.BindToType

' If the type isn't expected, then stop deserialization.

If typeName <> "BookRecord" AndAlso typeName <> "AisleLocation" AndAlso typeName <> "WarehouseLocation" Then

Return Nothing

End If

Return Binder.BindToType(assemblyName, typeName)

End Function

End Class

Public Class BookRecord

Public Property Title As String

Public Property Location As Location

End Class

Public MustInherit Class Location

Public Property StoreId As String

End Class

Public Class AisleLocation

Inherits Location

Public Property Aisle As Char

Public Property Shelf As Byte

End Class

Public Class WarehouseLocation

Inherits Location

Public Property Bay As String

Public Property Shelf As Byte

End Class

Public Class Binders

Public Shared Property BookRecord As ISerializationBinder = New BookRecordSerializationBinder()

End Class

Public Class ExampleClass

Public Function DeserializeBookRecord(s As String) As BookRecord

Dim settings As JsonSerializerSettings = New JsonSerializerSettings()

settings.TypeNameHandling = TypeNameHandling.Auto

' Ensure that SerializationBinder is non-null before deserializing

settings.SerializationBinder = If(Binders.BookRecord, New Exception("Expected non-null"))

Return JsonConvert.DeserializeObject(Of BookRecord)(s, settings)

End Function

End Class

相关规则

CA2326:请勿使用 None 以外的 TypeNameHandling 值

CA2327:不要使用不安全的 JsonSerializerSettings

CA2329:不要使用不安全的配置反序列化 JsonSerializer

CA2330:在反序列化时确保 JsonSerializer 具有安全配置

0 人点赞