CA2321:請勿使用 SimpleTypeResolver 搭配 JavaScriptSerializer 來還原序列化

屬性
規則識別碼 CA2321
標題 請勿使用 SimpleTypeResolver 搭配 JavaScriptSerializer 來還原序列化
類別 安全性
修正程式是中斷或非中斷 不中斷
預設在 .NET 8 中啟用 No

原因

使用 System.Web.Script.Serialization.JavaScriptSerializer 初始化 System.Web.Script.Serialization.SimpleTypeResolver之後,已呼叫或參考還原串行化方法。

根據預設,此規則會分析整個程式代碼基底,但這是可設定

檔案描述

還原序列化未受信任資料時,不安全的還原序列化程式會易受攻擊。 攻擊者可以修改序列化的資料,以包含非預期的型別,以插入具有惡意副作用的物件。 例如,對不安全還原串行化程式的攻擊可能會在基礎操作系統上執行命令、透過網路通訊或刪除檔案。

此規則會在System.Web.Script.Serialization.JavaScriptSerializer使用 System.Web.Script.Serialization.SimpleTypeResolver初始化 JavaScriptSerializer 之後,尋找還原串行化方法呼叫或參考。

如何修正違規

隱藏警告的時機

如果下列狀況,可以放心地隱藏此規則的警告:

  • 您知道輸入是受信任的。 請考慮應用程式的信任界限和數據流可能會隨著時間而變更。
  • 您已在如何修正違規採取其中一項預防措施。

隱藏警告

如果您只想要隱藏單一違規,請將預處理器指示詞新增至原始程式檔以停用,然後重新啟用規則。

#pragma warning disable CA2321
// The code that's violating the rule is on this line.
#pragma warning restore CA2321

若要停用檔案、資料夾或項目的規則,請在組態檔中將其嚴重性設定為 。none

[*.{cs,vb}]
dotnet_diagnostic.CA2321.severity = none

如需詳細資訊,請參閱 如何隱藏程式代碼分析警告

設定程式代碼以分析

使用下列選項來設定程式代碼基底要執行此規則的部分。

您可以只針對此規則、它套用的所有規則,或針對套用至此類別的所有規則(安全性)設定這些選項。 如需詳細資訊,請參閱 程式代碼品質規則組態選項

排除特定符號

您可以從分析中排除特定符號,例如類型和方法。 例如,若要指定規則不應該在名為 MyType的任何程式代碼上執行,請將下列機碼/值組新增至 專案中的 .editorconfig 檔案:

dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType

選項值中允許的符號名稱格式(以 |分隔):

  • 只包含符號名稱(包含名稱的所有符號,不論包含類型或命名空間為何)。
  • 符號 檔案識別碼格式的完整名稱。 每個符號名稱都需要符號種類前置詞,例如 M: 方法、 T: 類型和 N: 命名空間。
  • .ctor 用於建構函式和 .cctor 靜態建構函式。

範例:

選項值 摘要
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType 符合所有名為 MyType的符號。
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType1|MyType2 比對名為 MyType1MyType2的所有符號。
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) 比對特定方法和MyMethod1MyMethod2個別的完整簽章。

排除特定類型及其衍生類型

您可以從分析中排除特定類型及其衍生類型。 例如,若要指定規則不應該在具名 MyType 類型及其衍生型別內的任何方法上執行,請將下列機碼/值組新增至 專案中的 .editorconfig 檔案:

dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType

選項值中允許的符號名稱格式(以 |分隔):

  • 僅限類型名稱(包含名稱的所有類型,不論包含類型或命名空間為何)。
  • 符號 文件識別碼格式的完整名稱,具有選擇性 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 比對所有名為 MyType1MyType2 的型別,以及其所有衍生型別。
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 比對特定類型和MyType1MyType2個別的完整名稱,以及其所有衍生型別。

虛擬程式代碼範例

違規 1

using System.Web.Script.Serialization;

public class ExampleClass
{
    public T Deserialize<T>(string str)
    {
        JavaScriptSerializer s = new JavaScriptSerializer(new SimpleTypeResolver());
        return s.Deserialize<T>(str);
    }
}
Imports System.Web.Script.Serialization

Public Class ExampleClass
    Public Function Deserialize(Of T)(str As String) As T
        Dim s As JavaScriptSerializer = New JavaScriptSerializer(New SimpleTypeResolver())
        Return s.Deserialize(Of T)(str)
    End Function
End Class

解決方案 1

using System.Web.Script.Serialization;

public class ExampleClass
{
    public T Deserialize<T>(string str)
    {
        JavaScriptSerializer s = new JavaScriptSerializer();
        return s.Deserialize<T>(str);
    }
}
Imports System.Web.Script.Serialization

Public Class ExampleClass
    Public Function Deserialize(Of T)(str As String) As T
        Dim s As JavaScriptSerializer = New JavaScriptSerializer()
        Return s.Deserialize(Of T)(str)
    End Function
End Class

違規 2

using System.Web.Script.Serialization;

public class BookRecord
{
    public string Title { get; set; }
    public string Author { get; set; }
    public int PageCount { get; set; }
    public AisleLocation Location { get; set; }
}

public class AisleLocation
{
    public char Aisle { get; set; }
    public byte Shelf { get; set; }
}

public class ExampleClass
{
    public BookRecord DeserializeBookRecord(string s)
    {
        JavaScriptSerializer serializer = new JavaScriptSerializer(new SimpleTypeResolver());
        return serializer.Deserialize<BookRecord>(s);
    }
}
Imports System.Web.Script.Serialization

Public Class BookRecord
    Public Property Title As String
    Public Property Author As String
    Public Property Location As AisleLocation
End Class

Public Class AisleLocation
    Public Property Aisle As Char
    Public Property Shelf As Byte
End Class

Public Class ExampleClass
    Public Function DeserializeBookRecord(str As String) As BookRecord
        Dim serializer As JavaScriptSerializer = New JavaScriptSerializer(New SimpleTypeResolver())
        Return serializer.Deserialize(Of BookRecord)(str)
    End Function
End Class

解決方案 2

using System;
using System.Web.Script.Serialization;

public class BookRecordTypeResolver : JavaScriptTypeResolver
{
    // For compatibility with data serialized with a JavaScriptSerializer initialized with SimpleTypeResolver.
    private static readonly SimpleTypeResolver Simple = new SimpleTypeResolver();

    public override Type ResolveType(string id)
    {
        // One way to discover expected types is through testing deserialization
        // of **valid** data and logging the types used.

        ////Console.WriteLine($"ResolveType('{id}')");

        if (id == typeof(BookRecord).AssemblyQualifiedName || id == typeof(AisleLocation).AssemblyQualifiedName)
        {
            return Simple.ResolveType(id);
        }
        else
        {
            throw new ArgumentException("Unexpected type ID", nameof(id));
        }
    }

    public override string ResolveTypeId(Type type)
    {
        return Simple.ResolveTypeId(type);
    }
}

public class BookRecord
{
    public string Title { get; set; }
    public string Author { get; set; }
    public int PageCount { get; set; }
    public AisleLocation Location { get; set; }
}

public class AisleLocation
{
    public char Aisle { get; set; }
    public byte Shelf { get; set; }
}

public class ExampleClass
{
    public BookRecord DeserializeBookRecord(string s)
    {
        JavaScriptSerializer serializer = new JavaScriptSerializer(new BookRecordTypeResolver());
        return serializer.Deserialize<BookRecord>(s);
    }
}
Imports System
Imports System.Web.Script.Serialization

Public Class BookRecordTypeResolver
    Inherits JavaScriptTypeResolver

    ' For compatibility with data serialized with a JavaScriptSerializer initialized with SimpleTypeResolver.
    Private Dim Simple As SimpleTypeResolver = New SimpleTypeResolver()

    Public Overrides Function ResolveType(id As String) As Type
        ' One way to discover expected types is through testing deserialization
        ' of **valid** data and logging the types used.

        ''Console.WriteLine($"ResolveType('{id}')")

        If id = GetType(BookRecord).AssemblyQualifiedName Or id = GetType(AisleLocation).AssemblyQualifiedName Then
            Return Simple.ResolveType(id)
        Else
            Throw New ArgumentException("Unexpected type", NameOf(id))
        End If
    End Function

    Public Overrides Function ResolveTypeId(type As Type) As String
        Return Simple.ResolveTypeId(type)
    End Function
End Class

Public Class BookRecord
    Public Property Title As String
    Public Property Author As String
    Public Property Location As AisleLocation
End Class

Public Class AisleLocation
    Public Property Aisle As Char
    Public Property Shelf As Byte
End Class

Public Class ExampleClass
    Public Function DeserializeBookRecord(str As String) As BookRecord
        Dim serializer As JavaScriptSerializer = New JavaScriptSerializer(New BookRecordTypeResolver())
        Return serializer.Deserialize(Of BookRecord)(str)
    End Function
End Class

CA2322:還原序列化之前,請確定不會使用 SimpleTypeResolver 來將 JavaScriptSerializer 初始化