CA2328: Sicherstellen, dass JsonSerializerSettings sicher ist

Eigenschaft Wert
Regel-ID CA2328
Titel Sicherstellen, dass JsonSerializerSettings sicher ist
Kategorie Security
Fix führt oder führt nicht zur Unterbrechung Nicht unterbrechend
Standardmäßig in .NET 8 aktiviert Nein

Ursache

Diese Regel wird ausgelöst, wenn die beiden folgenden Bedingungen auf eine Instanz von Newtonsoft.Json.JsonSerializerSettingszutreffen könnten:

Die JsonSerializerSettings-Instanz muss auf eine der folgenden Arten verwendet werden:

Diese Regel ähnelt der Regel CA2327. In diesem Fall kann durch die Analyse jedoch nicht definitiv ermittelt werden, ob die Einstellungen unsicher sind.

Standardmäßig analysiert diese Regel die gesamte Codebasis, aber dieses Verhalten ist konfigurierbar.

Regelbeschreibung

Unsichere Deserialisierer sind beim Deserialisieren nicht vertrauenswürdiger Daten anfällig. Ein Angreifer könnte den serialisierten Daten unerwartete Datentypen hinzufügen, um Objekte mit schädlichen Auswirkungen einschleusen. Ein Angriff auf einen unsicheren Deserialisierer könnte z. B. Befehle auf dem dahinterliegenden Betriebssystem ausführen, über das Netzwerk kommunizieren oder Dateien löschen.

Diese Regel sucht Newtonsoft.Json.JsonSerializerSettings-Instanzen, die zum Deserialisieren von bei der Eingabe angegebenen Typen konfiguriert sein könnten, jedoch nicht zum Einschränken deserialisierter Typen mit einem Newtonsoft.Json.Serialization.ISerializationBinder. Wenn Sie die Deserialisierung von bei der Eingabe angegebenen Typen nicht zulassen möchten, deaktivieren Sie die Regeln CA2327, CA2328, CA2329 und CA2330, und aktivieren Sie stattdessen die Regel CA2326.

Behandeln von Verstößen

Wann sollten Warnungen unterdrückt werden?

Eine Warnung aus dieser Regel kann sicher unterdrückt werden, wenn Folgendes gilt:

Unterdrücken einer Warnung

Um nur eine einzelne Verletzung zu unterdrücken, fügen Sie der Quelldatei Präprozessoranweisungen hinzu, um die Regel zu deaktivieren und dann wieder zu aktivieren.

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

Um die Regel für eine Datei, einen Ordner oder ein Projekt zu deaktivieren, legen Sie den Schweregrad in der Konfigurationsdatei auf none fest.

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

Weitere Informationen finden Sie unter Vorgehensweise: Unterdrücken von Codeanalyse-Warnungen.

Konfigurieren des zu analysierenden Codes

Mithilfe der folgenden Optionen können Sie konfigurieren, für welche Teile Ihrer Codebasis diese Regel ausgeführt werden soll.

Sie können diese Optionen nur für diese Regel, für alle zutreffenden Regeln oder für alle zutreffenden Regeln in dieser Kategorie (Sicherheit) konfigurieren. Weitere Informationen finden Sie unter Konfigurationsoptionen für die Codequalitätsregel.

Ausschließen bestimmter Symbole

Sie können bestimmte Symbole, z. B. Typen und Methoden, von der Analyse ausschließen. Sie können beispielsweise festlegen, dass die Regel nicht für Code innerhalb von Typen namens MyType ausgeführt werden soll, indem Sie einer EDITORCONFIG-Datei in Ihrem Projekt das folgende Schlüssel-Wert-Paar hinzufügen:

dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType

Zulässige Formate für Symbolnamen im Optionswert (durch | getrennt):

  • Nur Symbolname (schließt alle Symbole mit dem Namen ein, unabhängig vom enthaltenden Typ oder Namespace)
  • Vollqualifizierte Namen im Format der Dokumentations-ID des Symbols Jeder Symbolname erfordert ein Symbolartpräfix, z. B. M: für Methoden, T: für Typen und N: für Namespaces.
  • .ctor für Konstruktoren und .cctor für statische Konstruktoren

Beispiele:

Optionswert Zusammenfassung
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType Trifft auf alle Symbole namens MyType zu
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType1|MyType2 Trifft auf alle Symbole namens MyType1 oder MyType2 zu
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS.MyType.MyMethod(ParamType) Trifft speziell auf die Methode MyMethod mit der angegebenen vollqualifizierten Signatur zu
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS1.MyType1.MyMethod1(ParamType)|M:NS2.MyType2.MyMethod2(ParamType) Trifft speziell auf die Methoden MyMethod1 und MyMethod2 mit den jeweiligen vollqualifizierten Signaturen zu

Ausschließen bestimmter Typen und von diesen abgeleiteten Typen

Sie können bestimmte Typen und von diesen abgeleitete Typen aus der Analyse ausschließen. Wenn Sie z. B. festlegen möchten, dass die Regel nicht für Methoden innerhalb von MyType-Typen und von diesen abgeleiteten Typen ausgeführt werden soll, fügen Sie einer EDITORCONFIG-Datei in Ihrem Projekt das folgende Schlüssel-Wert-Paar hinzu:

dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType

Zulässige Formate für Symbolnamen im Optionswert (durch | getrennt):

  • Nur Typname (schließt alle Typen mit dem Namen ein, unabhängig vom enthaltenden Typ oder Namespace)
  • Vollqualifizierte Namen im Dokumentations-ID-Format des Symbols mit einem optionalen Präfix T:

Beispiele:

Optionswert Zusammenfassung
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType Stimmt mit allen MyType-Typen und allen von diesen abgeleiteten Typen überein.
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType1|MyType2 Stimmt mit allen MyType1- oder MyType2-Typen und allen von diesen abgeleiteten Typen überein.
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS.MyType Stimmt mit einem bestimmten MyType-Typ mit einem angegebenen vollqualifizierten Namen und allen von diesem abgeleiteten Typen überein.
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS1.MyType1|M:NS2.MyType2 Stimmt mit bestimmten MyType1- und MyType2-Typen mit den entsprechenden vollqualifizierten Namen und allen von diesen abgeleiteten Typen überein.

Pseudocodebeispiele

Verletzung

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

Lösung

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: Keine anderen TypeNameHandling-Werte als None (Keine) verwenden

CA2327: Keine unsichere JsonSerializerSettings-Klasse verwenden

CA2329: Nicht mit JsonSerializer mit unsicherer Konfiguration deserialisieren

CA2330: Sicherstellen, dass JsonSerializer eine sichere Konfiguration bei der Deserialisierung verwendet