Share via


CA2321: SimpleTypeResolver를 사용하여 JavaScriptSerializer로 역직렬화하지 마세요.

속성
규칙 ID CA2321
타이틀 SimpleTypeResolver를 사용하여 JavaScriptSerializer를 통해 역직렬화하지 마세요.
범주 보안
수정 사항이 주요 변경인지 여부 주요 변경 아님
.NET 8에서 기본적으로 사용 아니요

원인

System.Web.Script.Serialization.SimpleTypeResolver를 사용하여 초기화한 후 System.Web.Script.Serialization.JavaScriptSerializer deserialization 메서드가 호출되었거나 참조되었습니다.

기본적으로 이 규칙은 전체 코드베이스를 분석하지만 이는 구성 가능합니다.

규칙 설명

안전하지 않은 역직렬 변환기는 신뢰할 수 없는 데이터를 역직렬화할 때 취약합니다. 공격자는 예기치 않은 형식을 포함하도록 직렬화된 데이터를 수정하여 악의적인 부작용을 개체에 주입할 수 있습니다. 예를 들어 안전하지 않은 역직렬 변환기에 대한 공격은 기본 운영 체제에서 명령을 실행하거나, 네트워크를 통해 통신하거나, 파일을 삭제할 수 있습니다.

이 규칙은 System.Web.Script.Serialization.SimpleTypeResolver를 사용하여 JavaScriptSerializer를 초기화한 후 System.Web.Script.Serialization.JavaScriptSerializer deserialization 메서드 호출 또는 참조를 찾습니다.

위반 문제를 해결하는 방법

  • System.Web.Script.Serialization.SimpleTypeResolverJavaScriptTypeResolver를 초기화하지 않습니다.
  • 코드가 SimpleTypeResolver를 사용하여 직렬화된 데이터를 읽어야 하는 경우 사용자 지정 JavaScriptTypeResolver를 구현하여 역직렬화된 형식을 예상 목록으로 제한합니다.
  • 직렬화된 데이터를 변조 방지로 설정합니다. serialization 후에 직렬화된 데이터에 암호화된 방식으로 서명합니다. deserialization 전에 암호화 시그니처의 유효성을 검사합니다. 암호화 키가 공개되지 않도록 보호하고 키 순환을 설계합니다.

경고를 표시하지 않는 경우

다음 경우에는 이 규칙의 경고를 표시하지 않아도 됩니다.

  • 입력을 신뢰할 수 있습니다. 애플리케이션의 트러스트 경계 및 데이터 흐름이 시간이 지남에 따라 달라질 수 있다는 점을 고려합니다.
  • 위반 문제를 해결하는 방법의 예방 조치 중 하나를 수행했습니다.

경고 표시 안 함

단일 위반만 표시하지 않으려면 원본 파일에 전처리기 지시문을 추가하여 규칙을 사용하지 않도록 설정한 후 다시 사용하도록 설정합니다.

#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

옵션 값의 허용되는 기호 이름 형식(|로 구분):

  • 기호 이름만(포함하는 형식 또는 네임스페이스와 관계없이 해당 이름의 모든 기호 포함).
  • 기호의 설명서 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) 특정 메서드 MyMethod1MyMethod2를 개별 정규화된 시그니처와 비교합니다.

특정 형식 및 해당 파생 형식 제외

분석에서 특정 형식과 해당 파생 형식을 제외할 수 있습니다. 예를 들어 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 형식 및 모든 해당 파생 형식과 일치합니다.

의사 코드 예제

위반 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: 역직렬화하기 전에 JavaScriptSerializer가 SimpleTypeResolver로 초기화되지 않았는지 확인합니다.