CA2322 : Assurez-vous que JavaScriptSerializer n’est pas initialisé avec SimpleTypeResolver avant la désérialisation

Propriété Value
Identificateur de la règle CA2322
Titre Assurez-vous que JavaScriptSerializer n’est pas initialisé avec SimpleTypeResolver avant la désérialisation
Catégorie Sécurité
Le correctif est cassant ou non cassant Sans rupture
Activé par défaut dans .NET 8 Non

Cause

Une méthode de désérialisation System.Web.Script.Serialization.JavaScriptSerializer a été appelée ou référencée et JavaScriptSerializer a peut-être été initialisée avec un System.Web.Script.Serialization.SimpleTypeResolver.

Par défaut, cette règle analyse l’intégralité du codebase, mais elle est configurable.

Description de la règle

Les désérialiseurs non sécurisés sont vulnérables lors de la désérialisation de données non approuvées. Un attaquant peut modifier les données sérialisées pour y inclure des types inattendus afin d’injecter des objets avec des effets secondaires malveillants. Une attaque contre un désérialiseur non sécurisé peut, par exemple, exécuter des commandes sur le système d’exploitation sous-jacent, communiquer sur le réseau ou supprimer des fichiers.

Cette règle recherche des appels ou références à la méthode de désérialisation System.Web.Script.Serialization.JavaScriptSerializer, lorsque JavaScriptSerializer a peut-être été initialisé avec un System.Web.Script.Serialization.SimpleTypeResolver.

Comment corriger les violations

  • Assurez-vous que les objets JavaScriptTypeResolver ne sont pas initialisés avec un System.Web.Script.Serialization.SimpleTypeResolver.
  • Si votre code doit lire les données sérialisées à l’aide d’un SimpleTypeResolver, limitez les types désérialisés à une liste attendue en implémentant un JavaScriptTypeResolver personnalisé.
  • Rendez les données sérialisées inviolables. Après la sérialisation, signez par chiffrement les données sérialisées. Avant la désérialisation, validez la signature de chiffrement. Protégez la clé de chiffrement contre la divulgation, et concevez un mécanisme de permutation des clés.

Quand supprimer les avertissements

Vous pouvez supprimer sans risque un avertissement de cette règle si :

  • Vous savez que l’entrée est approuvée. Considérez que la limite d’approbation et les flux de données de votre application peuvent changer au fil du temps.
  • Vous avez pris l’une des précautions décrites dans Comment corriger les violations.

Supprimer un avertissement

Si vous voulez supprimer une seule violation, ajoutez des directives de préprocesseur à votre fichier source pour désactiver et réactiver la règle.

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

Pour désactiver la règle sur un fichier, un dossier ou un projet, définissez sa gravité sur none dans le fichier de configuration.

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

Pour plus d’informations, consultez Comment supprimer les avertissements de l’analyse de code.

Configurer le code à analyser

Utilisez l’option suivante pour configurer les parties de votre codebase sur lesquelles exécuter cette règle.

Vous pouvez configurer ces options pour cette règle uniquement, pour toutes les règles auxquelles elles s’appliquent ou pour toutes les règles de cette catégorie (Sécurité) auxquelles elles s’appliquent. Pour plus d’informations, consultez Options de configuration des règles de qualité du code.

Exclure des symboles spécifiques

Vous pouvez exclure de l’analyse des symboles spécifiques, comme des types et des méthodes. Par exemple, pour spécifier que la règle ne doit pas s’exécuter sur du code dans des types nommés MyType, ajoutez la paire clé-valeur suivante à un fichier .editorconfig dans votre projet :

dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType

Formats de nom de symbole autorisés dans la valeur d’option (séparés par |) :

  • Nom du symbole uniquement (inclut tous les symboles avec le nom, quel que soit le type ou l’espace de noms qui les contient).
  • Noms qualifiés complets au format d’ID de documentation du symbole. Chaque nom de symbole nécessite un préfixe de type symbole, comme M: pour les méthodes, T: pour les types et N: pour les espaces de noms.
  • .ctor pour les constructeurs et .cctor pour les constructeurs statiques.

Exemples :

Valeur d’option Récapitulatif
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType Correspond à tous les symboles nommés MyType.
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType1|MyType2 Correspond à tous les symboles nommés MyType1 ou MyType2.
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS.MyType.MyMethod(ParamType) Correspond à une méthode MyMethod spécifique avec la signature complète spécifiée.
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS1.MyType1.MyMethod1(ParamType)|M:NS2.MyType2.MyMethod2(ParamType) Correspond à des méthodes MyMethod1 et MyMethod2 spécifiques avec la signature complète spécifiée.

Exclure des types spécifiques et leurs types dérivés

Vous pouvez exclure de l’analyse des types spécifiques et leurs types dérivés. Par exemple, pour spécifier que la règle ne doit s’exécuter sur aucune méthode dans des types nommés MyType et leurs types dérivés, ajoutez la paire clé-valeur suivante à un fichier .editorconfig dans votre projet :

dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType

Formats de nom de symbole autorisés dans la valeur d’option (séparés par |) :

  • Nom du type uniquement (inclut tous les types avec le nom, quel que soit le type ou l’espace de noms qui les contient).
  • Noms qualifiés complets au format d’ID de documentation du symbole, avec un préfixe T: facultatif.

Exemples :

Valeur d’option Récapitulatif
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType Correspond à tous les types nommés MyType et à tous leurs types dérivés.
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType1|MyType2 Correspond à tous les types nommés MyType1 ou MyType2, et à tous leurs types dérivés.
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS.MyType Correspond à un type MyType spécifique avec un nom complet donné et tous ses types dérivés.
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS1.MyType1|M:NS2.MyType2 Correspond à des types MyType1 ou MyType2 spécifiques avec leur nom complet respectif et tous leurs types dérivés.

Exemples de pseudo-code

Violation 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

Solution 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

Violation 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

Solution 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 : Ne désérialisez avec JavaScriptSerializer à l’aide de SimpleTypeResolver