CA2302: BinaryFormatter.Deserialize çağrılmadan önce BinaryFormatter.Binder'ın ayarlandığından emin olun

Özellik Değer
Kural Kimliği CA2302
Başlık BinaryFormatter.Deserialize çağırmadan önce BinaryFormatter.Binder öğesinin ayarlandığından emin olun
Kategori Güvenlik
Düzeltme bozucu ya da bozmayan olabilir Kesintisiz
.NET 10'da varsayılan olarak etkin Hayır
Geçerli diller C# ve Visual Basic

Neden

Bir System.Runtime.Serialization.Formatters.Binary.BinaryFormatter serileştirme durumundan çıkarma yöntemi çağrıldı veya atıfta bulunuldu ve Binder özelliği null olabilir.

Bu kural CA2301'e benzer, ancak çözümleme kesinlikle null olup olmadığını Binder belirleyemez.

Varsayılan olarak, bu kural tüm kod tabanını analiz eder, ancak bu yapılandırılabilir.

Uyarı

SerializationBinder ile türleri kısıtlamak tüm saldırıları önleyemez. Daha fazla bilgi için bkz . BinaryFormatter güvenlik kılavuzu.

Kural açıklaması

Güvenilmeyen verilerin seri durumdan çıkarılması sırasında güvenli olmayan seri durumdan çıkarıcılar savunmasızdır. Saldırgan, kötü amaçlı yan etkilere sahip nesneler eklemek için seri hale getirilmiş verileri beklenmeyen türler içerecek şekilde değiştirebilir. Güvenli olmayan bir seri durumdan çıkarıcıya yönelik bir saldırı, örneğin, temel işletim sisteminde komut yürütebilir, ağ üzerinden iletişim kurabilir veya dosyaları silebilir.

Bu kural, System.Runtime.Serialization.Formatters.Binary.BinaryFormatter seri durumdan çıkarma yöntemi çağrılarını veya referanslarını, Binder'in null olabileceği durumlarda bulur. Özelliğinden bağımsız olarak BinaryFormatter seri durumdan çıkarma Binder işlemine izin vermek istemiyorsanız, bu kuralı ve CA2301'i devre dışı bırakın ve CA2300 kuralını etkinleştirin.

İhlalleri düzeltme

  • Bunun yerine güvenli bir seri hale getirici kullanın ve bir saldırganın serileştirilmiş verileri rastgele bir türe dönüştürmesine izin vermeyin. Daha fazla bilgi için bkz . Tercih edilen alternatifler.
  • Serileştirilmiş verilerin kurcalanmaya karşı dayanıklı olmasını sağlayın. Serileştirmeden sonra, serileştirilmiş verileri şifreli olarak imzalayın. Seri durumdan çıkarmadan önce kriptografik imzayı doğrulayın. Şifreleme anahtarının açıklanmasını önleyip anahtar döndürmeleri için tasarım yapma.
  • Bu seçenek, gelecekte kodu hizmet reddi saldırılarına ve olası uzaktan kod yürütme saldırılarına karşı savunmasız hale getirir. Daha fazla bilgi için bkz . BinaryFormatter güvenlik kılavuzu. Deserialize edilmiş türleri kısıtlayın. Bir özel System.Runtime.Serialization.SerializationBinder uygulayın. Serileştirmeyi geri almadan önce, Binder özelliğini tüm kod yollarında kendi özel SerializationBinder örneğinize ayarlayın. Geçersiz kılınan BindToType yönteminde, tür beklenmeyense seri durumdan çıkarma işlemini durdurmak için bir istisna atın.

Uyarıların ne zaman bastırılması gerekiyor?

BinaryFormatter güvenli değildir ve güvenli hale getirilemiyor.

Kod çözümleme için konfigüre et

Bu kuralın kod tabanınızın hangi bölümlerinde çalıştırılacaklarını yapılandırmak için aşağıdaki seçenekleri kullanın.

Bu seçenekleri yalnızca bu kural için, uyguladıkları tüm kurallar için veya bu kategorideki tüm kurallar için (Güvenlik) yapılandırabilirsiniz. Daha fazla bilgi için bkz . Kod kalitesi kuralı yapılandırma seçenekleri.

Belirli simgeleri hariç tutma

excluded_symbol_names seçeneğini ayarlayarak türler ve yöntemler gibi belirli simgeleri analizden hariç tutabilirsiniz. Örneğin, kuralın adlı MyTypetürlerdeki herhangi bir kodda çalışmaması gerektiğini belirtmek için, projenizdeki bir .editorconfig dosyasına aşağıdaki anahtar-değer çiftini ekleyin:

dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType

Not

XXXX CAXXXX bölümünü geçerli kuralın kimliğiyle değiştirin.

Seçenek değerinde izin verilen simge adı biçimleri (ile |ayrılmış):

  • Yalnızca sembol adı (içerildiği tür veya ad alanından bağımsız olarak ada sahip tüm simgeleri içerir).
  • Simgelerin dökümantasyon kimliği formatındaki tam adlar. Her sembol adı için, yöntemler için M:, türler için T:, ve ad alanları için N: gibi bir sembol türü ön eki gerekir.
  • .ctor oluşturucular ve .cctor statik oluşturucular için.

Örnekler:

Seçenek Değeri Özet
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType adlı MyTypetüm simgelerle eşleşir.
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType1|MyType2 MyType1 veya MyType2 adlı tüm simgelerle eşleşir.
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS.MyType.MyMethod(ParamType) Belirtilen tam imza ile belirli bir yöntemi MyMethod eşleştirir.
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS1.MyType1.MyMethod1(ParamType)|M:NS2.MyType2.MyMethod2(ParamType) Belirli yöntemlerle MyMethod1 ve MyMethod2 ilgili tam imzalarla eşleşir.

Belirli türleri ve türetilmiş türlerini dışlama

excluded_type_names_with_derived_types seçeneğini ayarlayarak belirli türleri ve türetilmiş türlerini analizden dışlayabilirsiniz. Örneğin, kuralın adlı MyType ve türetilmiş türleri içindeki hiçbir yöntemde çalışmaması gerektiğini belirtmek için, projenizdeki bir .editorconfig dosyasına aşağıdaki anahtar-değer çiftini ekleyin:

dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType

Not

XXXX CAXXXX bölümünü geçerli kuralın kimliğiyle değiştirin.

Seçenek değerinde izin verilen simge adı biçimleri (ile |ayrılmış):

  • Yalnızca tür adı (içeren tür veya ad alanına bakılmaksızın adı olan tüm türleri içerir).
  • Simgenin belge kimliği biçiminde, isteğe bağlı T: ön ek içeren tam adlar.

Örnekler:

Seçenek değeri Özet
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType Adı MyType olan tüm türleri ve türevlerini eşleştirir.
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType1|MyType2 MyType1 veya MyType2 adlı tüm türleri ve bunların türetilmiş türlerinin tamamını eşleştirir.
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS.MyType Belirli bir türü MyType verilen tam adla ve türetilmiş tüm türleriyle eşleştirir.
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS1.MyType1|M:NS2.MyType2 Belirli türler MyType1 ve MyType2 ile bunların türetilmiş tüm türleri, ilgili tam adlarla eşleşir.

Sahte kod örnekleri

İhlal 1

using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

public class BookRecordSerializationBinder : SerializationBinder
{
    public override Type BindToType(string assemblyName, string typeName)
    {
        // One way to discover expected types is through testing deserialization
        // of **valid** data and logging the types used.

        ////Console.WriteLine($"BindToType('{assemblyName}', '{typeName}')");

        if (typeName == "BookRecord")
        {
            return typeof(BookRecord);
        }
        else if (typeName == "AisleLocation")
        {
            return typeof(AisleLocation);
        }
        else
        {
            throw new ArgumentException("Unexpected type", nameof(typeName));
        }
    }
}

[Serializable]
public class BookRecord
{
    public string Title { get; set; }
    public AisleLocation Location { get; set; }
}

[Serializable]
public class AisleLocation
{
    public char Aisle { get; set; }
    public byte Shelf { get; set; }
}

public class Binders
{
    public static SerializationBinder BookRecord =
        new BookRecordSerializationBinder();
}

public class ExampleClass
{
    public BookRecord DeserializeBookRecord(byte[] bytes)
    {
        BinaryFormatter formatter = new BinaryFormatter();
        formatter.Binder = Binders.BookRecord;
        using (MemoryStream ms = new MemoryStream(bytes))
        {
            return (BookRecord)formatter.Deserialize(ms);    // CA2302 violation
        }
    }
}
Imports System
Imports System.IO
Imports System.Runtime.Serialization
Imports System.Runtime.Serialization.Formatters.Binary

Public Class BookRecordSerializationBinder
    Inherits SerializationBinder

    Public Overrides Function BindToType(assemblyName As String, typeName As String) As Type
        ' One way to discover expected types is through testing deserialization
        ' of **valid** data and logging the types used.

        'Console.WriteLine($"BindToType('{assemblyName}', '{typeName}')")

        If typeName = "BinaryFormatterVB.BookRecord" Then
            Return GetType(BookRecord)
        Else If typeName = "BinaryFormatterVB.AisleLocation" Then
            Return GetType(AisleLocation)
        Else
            Throw New ArgumentException("Unexpected type", NameOf(typeName))
        End If
    End Function
End Class

<Serializable()>
Public Class BookRecord
    Public Property Title As String
    Public Property Location As AisleLocation
End Class

<Serializable()>
Public Class AisleLocation
    Public Property Aisle As Char
    Public Property Shelf As Byte
End Class

Public Class Binders
    Public Shared Property BookRecord As SerializationBinder = New BookRecordSerializationBinder()
End Class

Public Class ExampleClass
    Public Function DeserializeBookRecord(bytes As Byte()) As BookRecord
        Dim formatter As BinaryFormatter = New BinaryFormatter()
        formatter.Binder = Binders.BookRecord
        Using ms As MemoryStream = New MemoryStream(bytes)
            Return CType(formatter.Deserialize(ms), BookRecord)    ' CA2302 violation
        End Using
    End Function
End Class

1\. Çözüm

using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

public class BookRecordSerializationBinder : SerializationBinder
{
    public override Type BindToType(string assemblyName, string typeName)
    {
        // One way to discover expected types is through testing deserialization
        // of **valid** data and logging the types used.

        ////Console.WriteLine($"BindToType('{assemblyName}', '{typeName}')");

        if (typeName == "BookRecord")
        {
            return typeof(BookRecord);
        }
        else if (typeName == "AisleLocation")
        {
            return typeof(AisleLocation);
        }
        else
        {
            throw new ArgumentException("Unexpected type", nameof(typeName));
        }
    }
}

[Serializable]
public class BookRecord
{
    public string Title { get; set; }
    public AisleLocation Location { get; set; }
}

[Serializable]
public class AisleLocation
{
    public char Aisle { get; set; }
    public byte Shelf { get; set; }
}

public class Binders
{
    public static SerializationBinder BookRecord =
        new BookRecordSerializationBinder();
}

public class ExampleClass
{
    public BookRecord DeserializeBookRecord(byte[] bytes)
    {
        BinaryFormatter formatter = new BinaryFormatter();

        // Ensure that Binder is always non-null before deserializing
        formatter.Binder = Binders.BookRecord ?? throw new Exception("Expected non-null binder");

        using (MemoryStream ms = new MemoryStream(bytes))
        {
            return (BookRecord)formatter.Deserialize(ms);
        }
    }
}
Imports System
Imports System.IO
Imports System.Runtime.Serialization
Imports System.Runtime.Serialization.Formatters.Binary

Public Class BookRecordSerializationBinder
    Inherits SerializationBinder

    Public Overrides Function BindToType(assemblyName As String, typeName As String) As Type
        ' One way to discover expected types is through testing deserialization
        ' of **valid** data and logging the types used.

        'Console.WriteLine($"BindToType('{assemblyName}', '{typeName}')")

        If typeName = "BinaryFormatterVB.BookRecord" Then
            Return GetType(BookRecord)
        Else If typeName = "BinaryFormatterVB.AisleLocation" Then
            Return GetType(AisleLocation)
        Else
            Throw New ArgumentException("Unexpected type", NameOf(typeName))
        End If
    End Function
End Class

<Serializable()>
Public Class BookRecord
    Public Property Title As String
    Public Property Location As AisleLocation
End Class

<Serializable()>
Public Class AisleLocation
    Public Property Aisle As Char
    Public Property Shelf As Byte
End Class

Public Class Binders
    Public Shared Property BookRecord As SerializationBinder = New BookRecordSerializationBinder()
End Class

Public Class ExampleClass
    Public Function DeserializeBookRecord(bytes As Byte()) As BookRecord
        Dim formatter As BinaryFormatter = New BinaryFormatter()

        ' Ensure that Binder is always non-null before deserializing
        formatter.Binder = If(Binders.BookRecord, New Exception("Expected non-null"))

        Using ms As MemoryStream = New MemoryStream(bytes)
            Return CType(formatter.Deserialize(ms), BookRecord)
        End Using
    End Function
End Class

İhlal 2

using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

[Serializable]
public class BookRecord
{
    public string Title { get; set; }
    public AisleLocation Location { get; set; }
}

[Serializable]
public class AisleLocation
{
    public char Aisle { get; set; }
    public byte Shelf { get; set; }
}

public class ExampleClass
{
    public BinaryFormatter Formatter { get; set; }

    public BookRecord DeserializeBookRecord(byte[] bytes)
    {
        using (MemoryStream ms = new MemoryStream(bytes))
        {
            return (BookRecord) this.Formatter.Deserialize(ms);    // CA2302 violation
        }
    }
}
Imports System
Imports System.IO
Imports System.Runtime.Serialization.Formatters.Binary

<Serializable()>
Public Class BookRecord
    Public Property Title As String
    Public Property Location As AisleLocation
End Class

<Serializable()>
Public Class AisleLocation
    Public Property Aisle As Char
    Public Property Shelf As Byte
End Class

Public Class ExampleClass
    Public Property Formatter As BinaryFormatter

    Public Function DeserializeBookRecord(bytes As Byte()) As BookRecord
        Using ms As MemoryStream = New MemoryStream(bytes)
            Return CType(Me.Formatter.Deserialize(ms), BookRecord)    ' CA2302 violation
        End Using
    End Function
End Class

Çözüm 2

using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

public class BookRecordSerializationBinder : SerializationBinder
{
    public override Type BindToType(string assemblyName, string typeName)
    {
        // One way to discover expected types is through testing deserialization
        // of **valid** data and logging the types used.

        ////Console.WriteLine($"BindToType('{assemblyName}', '{typeName}')");

        if (typeName == "BookRecord")
        {
            return typeof(BookRecord);
        }
        else if (typeName == "AisleLocation")
        {
            return typeof(AisleLocation);
        }
        else
        {
            throw new ArgumentException("Unexpected type", nameof(typeName));
        }
    }
}

[Serializable]
public class BookRecord
{
    public string Title { get; set; }
    public AisleLocation Location { get; set; }
}

[Serializable]
public class AisleLocation
{
    public char Aisle { get; set; }
    public byte Shelf { get; set; }
}

public class ExampleClass
{
    public BookRecord DeserializeBookRecord(byte[] bytes)
    {
        BinaryFormatter formatter = new BinaryFormatter();
        formatter.Binder = new BookRecordSerializationBinder();
        using (MemoryStream ms = new MemoryStream(bytes))
        {
            return (BookRecord) formatter.Deserialize(ms);
        }
    }
}
Imports System
Imports System.IO
Imports System.Runtime.Serialization
Imports System.Runtime.Serialization.Formatters.Binary

Public Class BookRecordSerializationBinder
    Inherits SerializationBinder

    Public Overrides Function BindToType(assemblyName As String, typeName As String) As Type
        ' One way to discover expected types is through testing deserialization
        ' of **valid** data and logging the types used.

        'Console.WriteLine($"BindToType('{assemblyName}', '{typeName}')")

        If typeName = "BinaryFormatterVB.BookRecord" Then
            Return GetType(BookRecord)
        Else If typeName = "BinaryFormatterVB.AisleLocation" Then
            Return GetType(AisleLocation)
        Else
            Throw New ArgumentException("Unexpected type", NameOf(typeName))
        End If
    End Function
End Class

<Serializable()>
Public Class BookRecord
    Public Property Title As String
    Public Property Location As AisleLocation
End Class

<Serializable()>
Public Class AisleLocation
    Public Property Aisle As Char
    Public Property Shelf As Byte
End Class

Public Class ExampleClass
    Public Function DeserializeBookRecord(bytes As Byte()) As BookRecord
        Dim formatter As BinaryFormatter = New BinaryFormatter()
        formatter.Binder = New BookRecordSerializationBinder()
        Using ms As MemoryStream = New MemoryStream(bytes)
            Return CType(formatter.Deserialize(ms), BookRecord)
        End Using
    End Function
End Class