CA2302: Upewnij się, że parametr BinaryFormatter.Binder został ustawiony przed wywołaniem metody BinaryFormatter.Deserialize
Właściwości | Wartość |
---|---|
Identyfikator reguły | CA2302 |
Tytuł | Upewnij się, że właściwość BinaryFormatter.Binder jest ustawiona przed wywołaniem metody BinaryFormatter.Deserialize |
Kategoria | Bezpieczeństwo |
Poprawka powodująca niezgodność lub niezgodność | Niezgodność |
Domyślnie włączone na platformie .NET 9 | Nie. |
Przyczyna
Metoda System.Runtime.Serialization.Formatters.Binary.BinaryFormatter deserializacji została wywołana lub odwołana, a Binder właściwość może mieć wartość null.
Ta reguła jest podobna do CA2301, ale analiza nie może określić, czy wartość Binder jest zdecydowanie równa null.
Domyślnie ta reguła analizuje całą bazę kodu, ale można to skonfigurować.
Ostrzeżenie
Ograniczanie typów za pomocą klasy SerializationBinder nie może zapobiec wszystkim atakom. Aby uzyskać więcej informacji, zobacz Przewodnik po zabezpieczeniach BinaryFormatter.
Opis reguły
Niezabezpieczone deserializatory są podatne na deserializacji niezaufanych danych. Osoba atakująca może zmodyfikować serializowane dane w celu uwzględnienia nieoczekiwanych typów w celu wstrzyknięcia obiektów ze złośliwymi skutkami ubocznymi. Atak na niezabezpieczonego deserializatora może na przykład wykonywać polecenia w bazowym systemie operacyjnym, komunikować się za pośrednictwem sieci lub usuwać pliki.
Ta reguła znajduje System.Runtime.Serialization.Formatters.Binary.BinaryFormatter wywołania metody deserializacji lub odwołania, gdy Binder wartość może mieć wartość null. Jeśli chcesz uniemożliwić deserializacji BinaryFormatter niezależnie od Binder właściwości, wyłącz tę regułę i CA2301 i włącz regułę CA2300.
Jak naprawić naruszenia
- Zamiast tego użyj bezpiecznego serializatora i nie zezwalaj osobie atakującej na określenie dowolnego typu do deserializacji. Aby uzyskać więcej informacji, zobacz Preferowane alternatywy.
- Ustaw serializacji danych na dowód manipulacji. Po serializacji kryptograficznie podpisz serializowane dane. Przed deserializacji zweryfikuj podpis kryptograficzny. Ochrona klucza kryptograficznego przed ujawnieniem i projektowaniem rotacji kluczy.
- Ta opcja sprawia, że kod jest podatny na ataki typu "odmowa usługi" i możliwe ataki zdalnego wykonywania kodu w przyszłości. Aby uzyskać więcej informacji, zobacz Przewodnik po zabezpieczeniach BinaryFormatter. Ogranicz deserializowane typy. Zaimplementuj niestandardowy System.Runtime.Serialization.SerializationBinderelement . Przed deserializacji ustaw
Binder
właściwość na wystąpienie niestandardowe SerializationBinder we wszystkich ścieżkach kodu. W metodzie przesłoniętej BindToType , jeśli typ jest nieoczekiwany, należy zgłosić wyjątek, aby zatrzymać deserializacji.
Kiedy pomijać ostrzeżenia
BinaryFormatter
jest niezabezpieczony i nie można go zabezpieczyć.
Konfigurowanie kodu do analizowania
Użyj poniższych opcji, aby skonfigurować, które części bazy kodu mają być uruchamiane w tej regule.
Możesz skonfigurować te opcje tylko dla tej reguły, dla wszystkich reguł, do których ma ona zastosowanie, lub dla wszystkich reguł w tej kategorii (Zabezpieczenia), których dotyczy. Aby uzyskać więcej informacji, zobacz Opcje konfiguracji reguły jakości kodu.
Wykluczanie określonych symboli
Z analizy można wykluczyć określone symbole, takie jak typy i metody. Aby na przykład określić, że reguła nie powinna być uruchamiana w żadnym kodzie w typach o nazwie MyType
, dodaj następującą parę klucz-wartość do pliku editorconfig w projekcie:
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType
Dozwolone formaty nazw symboli w wartości opcji (oddzielone przez |
):
- Tylko nazwa symbolu (zawiera wszystkie symbole o nazwie, niezależnie od typu zawierającego lub przestrzeni nazw).
- W pełni kwalifikowane nazwy w formacie identyfikatora dokumentacji symbolu. Każda nazwa symboli wymaga prefiksu typu symboli, takiego jak
M:
metody,T:
dla typów iN:
przestrzeni nazw. .ctor
dla konstruktorów i.cctor
konstruktorów statycznych.
Przykłady:
Wartość opcji | Podsumowanie |
---|---|
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType |
Pasuje do wszystkich symboli o nazwie MyType . |
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType1|MyType2 |
Pasuje do wszystkich symboli o nazwie MyType1 lub MyType2 . |
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS.MyType.MyMethod(ParamType) |
Pasuje do określonej metody MyMethod z określonym w pełni kwalifikowanym podpisem. |
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS1.MyType1.MyMethod1(ParamType)|M:NS2.MyType2.MyMethod2(ParamType) |
Pasuje do określonych metod MyMethod1 i MyMethod2 z odpowiednimi w pełni kwalifikowanymi podpisami. |
Wykluczanie określonych typów i ich typów pochodnych
Z analizy można wykluczyć określone typy i ich typy pochodne. Aby na przykład określić, że reguła nie powinna być uruchamiana na żadnych metodach w typach nazwanych MyType
i ich typach pochodnych, dodaj następującą parę klucz-wartość do pliku .editorconfig w projekcie:
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType
Dozwolone formaty nazw symboli w wartości opcji (oddzielone przez |
):
- Nazwa typu (zawiera tylko wszystkie typy o nazwie, niezależnie od typu zawierającego lub przestrzeni nazw).
- W pełni kwalifikowane nazwy w formacie identyfikatora dokumentacji symbolu z opcjonalnym
T:
prefiksem.
Przykłady:
Wartość opcji | Podsumowanie |
---|---|
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType |
Pasuje do wszystkich typów nazwanych MyType i wszystkich ich typów pochodnych. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType1|MyType2 |
Dopasuje wszystkie typy o nazwie MyType1 lub MyType2 i wszystkie ich typy pochodne. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS.MyType |
Pasuje do określonego typu MyType z daną w pełni kwalifikowaną nazwą i wszystkimi jego typami pochodnymi. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS1.MyType1|M:NS2.MyType2 |
Pasuje do określonych typów MyType1 i MyType2 z odpowiednimi w pełni kwalifikowanymi nazwami i wszystkimi ich typami pochodnymi. |
Przykłady przykładów kodu przykładowego
Naruszenie 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
Rozwiązanie 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();
// 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
Naruszenie 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
Rozwiązanie 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