다음을 통해 공유


CA2328: JsonSerializerSettings가 안전한지 확인

속성
규칙 ID CA2328
제목 JsonSerializerSettings가 안전한지 확인하세요.
범주 보안
수정 사항이 주요 변경인지 여부 주요 변경 아님
.NET 9에서 기본적으로 사용 아니요

원인

이 규칙은 Newtonsoft.Json.JsonSerializerSettings 인스턴스에 대해 다음 두 조건이 모두 ‘충족될 때’ 발생합니다.

JsonSerializerSettings 인스턴스는 다음 방법 중 하나로 사용해야 합니다.

이 규칙은 CA2327과 유사하지만, 이 경우에 설정이 안전하지 않다면 분석으로 확인할 수 없습니다.

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

규칙 설명

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

이 규칙은 입력에서 지정 된 형식을 역직렬화하도록 구성 될 수 있지만 역직렬화된 형식을 로 제한 하도록 구성 될 수 있는 newtonsoft.json JsonSerializerSettings 인스턴스를 찾습니다. Newtonsoft.json. ISerializationBinder. 입력에서 지정된 형식의 deserialization을 완전히 허용하지 않으려면 규칙 CA2327, CA2328, CA2329, CA2330을 사용하지 않도록 설정하고 대신 규칙 CA2326을 사용하도록 설정합니다.

위반 문제를 해결하는 방법

경고를 표시하지 않는 경우

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

경고 표시 안 함

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

#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) 특정 메서드 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 형식 및 모든 해당 파생 형식과 일치합니다.

의사 코드 예제

위반

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로 역직렬화하지 마세요.

CA2330: 역직렬화할 때 JsonSerializer에 보안 구성이 있는지 확인합니다.