| 屬性 | 值 |
|---|---|
| 規則識別碼 | CA2322 |
| 職稱 | 在反序列化之前,請確保沒有用 SimpleTypeResolver 來初始化 JavaScriptSerializer。 |
| 類別 | 安全性 |
| 修正是造成中斷還是不中斷 | 不中斷 |
| 在 .NET 10 中預設啟用 | 否 |
| 適用語言 | C# 與 Visual Basic |
原因
System.Web.Script.Serialization.JavaScriptSerializer已呼叫或參考還原串行化方法,且 JavaScriptSerializer 可能已使用 System.Web.Script.Serialization.SimpleTypeResolver初始化。
根據預設,此規則會分析整個程式碼,但它是可配置的。
規則描述
還原序列化未受信任資料時,不安全的還原序列化程式會易受攻擊。 攻擊者可以修改序列化的資料,以包含非預期的型別,以插入具有惡意副作用的物件。 例如,對不安全還原串行化程式的攻擊可能會在基礎操作系統上執行命令、透過網路通訊或刪除檔案。
當 JavaScriptSerializer 可能已使用 System.Web.Script.Serialization.SimpleTypeResolver 初始化時,此規則會搜尋 System.Web.Script.Serialization.JavaScriptSerializer 的還原串行化方法呼叫或參考。
如何修正違規
- 確定 JavaScriptTypeResolver 物件不會使用 System.Web.Script.Serialization.SimpleTypeResolver初始化。
- 如果您的程式碼需要使用 SimpleTypeResolver 來讀取序列化的數據,請實作自定義 JavaScriptTypeResolver,將還原後的類型限制為預期的清單。
- 讓串行化的數據防竄改。 串行化之後,以密碼編譯方式簽署串行化的數據。 在反序列化之前,請先驗證加密簽章。 保護密碼編譯金鑰,避免洩漏金鑰,並設計金鑰輪替。
隱藏警告的時機
如果下列狀況,可以放心地隱藏此規則的警告:
- 您知道輸入是受信任的。 請考慮應用程式的信任界限和數據流可能會隨著時間而變更。
- 您已在如何修正違規中採取其中一項預防措施。
隱藏警告
如果您只想要隱藏單一違規,請將預處理器指示詞新增至原始程式檔以停用,然後重新啟用規則。
#pragma warning disable CA2322
// The code that's violating the rule is on this line.
#pragma warning restore CA2322
若要停用檔案、資料夾或專案的規則,請在組態檔中將其嚴重性設為 none。
[*.{cs,vb}]
dotnet_diagnostic.CA2322.severity = none
如需詳細資訊,請參閱 如何隱藏程式代碼分析警告。
設定程式代碼以分析
使用下列選項來設定程式代碼基底要執行此規則的部分。
您可以只針對此規則、套用至的所有規則,或套用至此類別的所有規則(安全性)設定這些選項。 如需詳細資訊,請參閱 程式代碼品質規則組態選項。
排除特定符號
您可以藉由設定 [excluded_symbol_names] 選項,從分析中排除特定符號,例如類型和方法。 例如,若要指定規則不應該在名為 MyType的任何程式代碼上執行,請將下列機碼/值組新增至 專案中的 .editorconfig 檔案:
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType
注意
以適用規則的標識碼取代 XXXX 的 CAXXXX 部分。
選項值中允許的符號名稱格式(以 |分隔):
- 只含符號名稱(包括名稱的所有符號,不論其所屬類型或命名空間)。
- 符號的 文件識別碼格式中的完整名稱。 每個符號名稱都需要符號種類前置詞,例如
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,及其各自的完整簽章。 |
排除特定類型及其衍生類型
您可以藉由設定 [excluded_type_names_with_derived_types] 選項,從分析中排除特定類型及其衍生類型。 例如,若要指定規則不應該在具名 MyType 類型及其衍生型別內的任何方法上執行,請將下列機碼/值組新增至 專案中的 .editorconfig 檔案:
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType
注意
以適用規則的標識碼取代 XXXX 的 CAXXXX 部分。
選項值中允許的符號名稱格式(以 |分隔):
- 僅輸入類型名稱(包含該名稱的所有類型,不論包含類型或命名空間為何)。
- 符號的 文件識別碼格式中的完整限定名稱,具有可選的
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 及其所有衍生類型的完整名稱。 |
虛擬程式代碼範例
違規 1
using System.Web.Script.Serialization;
public class ExampleClass
{
public JavaScriptSerializer Serializer { get; set; }
public T Deserialize<T>(string str)
{
return this.Serializer.Deserialize<T>(str);
}
}
Imports System.Web.Script.Serialization
Public Class ExampleClass
Public Property Serializer As JavaScriptSerializer
Public Function Deserialize(Of T)(str As String) As T
Return Me.Serializer.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 JavaScriptSerializer Serializer { get; set; }
public BookRecord DeserializeBookRecord(string s)
{
return this.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 Property Serializer As JavaScriptSerializer
Public Function DeserializeBookRecord(str As String) As BookRecord
Return Me.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
相關規則
CA2321:不得使用 SimpleTypeResolver 搭配 JavaScriptSerializer 來進行反序列化