CA2328: JsonSerializerSettings が安全であることを確認してください
プロパティ | 値 |
---|---|
ルール ID | CA2328 |
Title | JsonSerializerSettings が安全であることを確認してください |
[カテゴリ] | Security |
修正が中断か中断なしであるか | なし |
.NET 8 では既定で有効 | いいえ |
原因
この規則は、Newtonsoft.Json.JsonSerializerSettings インスタンスに対して次の両方の条件が当てはまる "可能性がある" 場合に適用されます。
- TypeNameHandling プロパティが
None
以外の値である。 - SerializationBinder プロパティが null 値である。
JsonSerializerSettings インスタンスは、次のいずれかの方法で使用する必要があります。
- クラス フィールドまたはプロパティとして初期化する。
- メソッドによって返す。
- JsonSerializer.Create または JsonSerializer.CreateDefault に渡す。
- JsonSerializerSettings パラメーターを持つ JsonConvert メソッド に渡す。
この規則は CA2327 に似ていますが、この場合は、設定が安全でないかどうかを分析で明確に判断することはできません。
既定で、このルールではコードベース全体を分析しますが、これは構成可能です。
規則の説明
安全でない逆シリアライザーは、信頼されていないデータを逆シリアル化するときに脆弱です。 攻撃者がシリアル化されたデータを変更して予期されない型を追加し、悪意のある副作用を持つオブジェクトを挿入する可能性があります。 たとえば、安全でない逆シリアライザーに対する攻撃では、基になるオペレーティング システムでコマンドが実行されたり、ネットワークを介して通信されたり、ファイルを削除されたりする可能性があります。
この規則では、入力で指定された型を逆シリアル化するように構成されている可能性があるが、逆シリアル化される型を Newtonsoft.Json.Serialization.ISerializationBinder を使用して制限するように構成されていないことも考えられる Newtonsoft.Json.JsonSerializerSettings インスタンスを検索します。 入力で指定された型の逆シリアル化を完全に許可しない場合は、規則 CA2327、CA2328、CA2329、および CA2330 を無効にし、代わりに規則 CA2326 を有効にします。
違反の修正方法
- 可能な場合は、TypeNameHandling の
None
値を使用します。 - シリアル化されたデータを改ざん防止にします。 シリアル化後に、シリアル化されたデータに暗号化署名します。 逆シリアル化する前に、暗号化署名を検証します。 暗号化キーの開示を防止し、キーのローテーションを設計します。
- 逆シリアル化された型を制限します。 カスタム Newtonsoft.Json.Serialization.ISerializationBinder を実装します。 Json.NET を使用して逆シリアル化する前に、カスタム ISerializationBinder を Newtonsoft.Json.JsonSerializerSettings.SerializationBinder プロパティ内で確実に指定します。 オーバーライドされた Newtonsoft.Json.Serialization.ISerializationBinder.BindToType メソッドでは、型が予期したものでない場合、
null
を返すか、例外をスローして逆シリアル化を停止します。
どのようなときに警告を抑制するか
次の場合は、このルールの警告を抑制できます。
- 入力が信頼されていることがわかっている。 アプリケーションの信頼境界とデータ フローは時間の経過と共に変わる可能性があることを考慮する。
- 違反を修正する方法のいずれかの予防措置を講じた。
- TypeNameHandling プロパティが
None
以外の値である場合、 Newtonsoft.Json.JsonSerializerSettings.SerializationBinder プロパティが常に設定されることがわかっている。
警告を抑制する
単一の違反を抑制するだけの場合は、ソース ファイルにプリプロセッサ ディレクティブを追加して無効にしてから、規則をもう一度有効にします。
#pragma warning disable CA2328
// The code that's violating the rule is on this line.
#pragma warning restore CA2328
ファイル、フォルダー、またはプロジェクトの規則を無効にするには、構成ファイルでその重要度を none
に設定します。
[*.{cs,vb}]
dotnet_diagnostic.CA2328.severity = none
詳細については、「コード分析の警告を抑制する方法」を参照してください。
分析するコードを構成する
次のオプションを使用して、コードベースのどの部分に対してこのルールを実行するかを構成します。
これらのオプションを構成できる対象は、この規則だけ、それを適用するすべての規則、それを適用するこのカテゴリ (セキュリティ) のすべての規則のいずれかです。 詳細については、「コード品質規則の構成オプション」を参照してください。
特定のシンボルを除外する
型やメソッドなど、特定のシンボルを分析から除外することができます。 たとえば、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 で使用されている場合は、逆シリアル化を行わないでください
.NET