CA2302: Před voláním BinaryFormatter.Deserialize se ujistěte, že je nastaven binaryFormatter.Binder
Vlastnost | Hodnota |
---|---|
ID pravidla | CA2302 |
Název | Než zavoláte BinaryFormatter.Deserialize, ujistěte se, že je nastavený BinaryFormatter.Binder |
Kategorie | Zabezpečení |
Oprava způsobující chybu nebo chybu způsobující chybu | Nenarušující |
Povoleno ve výchozím nastavení v .NET 8 | No |
Příčina
Byla System.Runtime.Serialization.Formatters.Binary.BinaryFormatter volána nebo odkazována metoda deserializace a Binder vlastnost může být null.
Toto pravidlo je podobné ca2301, ale analýza nedokáže určit, jestli Binder je hodnota rozhodně null.
Ve výchozím nastavení toto pravidlo analyzuje celý základ kódu, ale dá se nakonfigurovat.
Upozorňující
Omezení typů pomocí SerializationBinder nemůže zabránit všem útokům. Další informace naleznete v průvodci zabezpečením BinaryFormatter.
Popis pravidla
Nezabezpečené deserializátory jsou zranitelné při deserializaci nedůvěryhodných dat. Útočník by mohl serializovaná data upravit tak, aby zahrnovala neočekávané typy pro vložení objektů se škodlivými vedlejšími účinky. Útok na nezabezpečený deserializátor může například spouštět příkazy v podkladovém operačním systému, komunikovat přes síť nebo odstraňovat soubory.
Toto pravidlo najde System.Runtime.Serialization.Formatters.Binary.BinaryFormatter volání metody deserializace nebo odkazy, pokud Binder může mít hodnotu null. Pokud chcete zakázat jakoukoli deserializaci bez BinaryFormatterBinder ohledu na vlastnost, zakažte toto pravidlo a CA2301 a povolte pravidlo CA2300.
Jak opravit porušení
- Místo toho použijte zabezpečený serializátor a nepovolte útočníkovi zadat libovolný typ deserializace. Další informace najdete v upřednostňovaných alternativách.
- Zfalšujte serializovaná data a zfalšujte je. Po serializaci kryptograficky podepisujte serializovaná data. Před deserializací ověřte kryptografický podpis. Chraňte kryptografický klíč před zveřejněním a návrhem obměny klíčů.
- Díky této možnosti je kód v budoucnu zranitelný vůči útokům na dostupnost služby a možným útokům vzdáleného spuštění kódu. Další informace naleznete v průvodci zabezpečením BinaryFormatter. Omezit deserializované typy Implementace vlastního System.Runtime.Serialization.SerializationBindersouboru . Před deserializací nastavte
Binder
vlastnost na instanci vlastní SerializationBinder ve všech cestách kódu. V přepsání BindToType metoda, pokud typ je neočekávaný, vyvolá výjimku pro zastavení deserializace.
Kdy potlačit upozornění
BinaryFormatter
je nezabezpečený a nedá se zabezpečit.
Konfigurace kódu pro analýzu
Pomocí následujících možností můžete nakonfigurovat, pro které části základu kódu se má toto pravidlo spouštět.
Tyto možnosti můžete nakonfigurovat jenom pro toto pravidlo, pro všechna pravidla, která platí, nebo pro všechna pravidla v této kategorii (zabezpečení), na která platí. Další informace naleznete v tématu Možnosti konfigurace pravidla kvality kódu.
Vyloučení konkrétních symbolů
Z analýzy můžete vyloučit konkrétní symboly, jako jsou typy a metody. Pokud chcete například určit, že pravidlo by se nemělo spouštět u žádného kódu v rámci pojmenovaných MyType
typů, přidejte do souboru .editorconfig v projektu následující dvojici klíč-hodnota:
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType
Povolené formáty názvů symbolů v hodnotě možnosti (oddělené ):|
- Pouze název symbolu (zahrnuje všechny symboly s názvem bez ohledu na typ nebo obor názvů).
- Plně kvalifikované názvy ve formátu ID dokumentace symbolu. Každý název symbolu vyžaduje předponu typu symbolu, například
M:
pro metody,T:
typy aN:
obory názvů. .ctor
pro konstruktory a.cctor
statické konstruktory.
Příklady:
Hodnota možnosti | Shrnutí |
---|---|
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType |
Odpovídá všem symbolům s názvem MyType . |
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType1|MyType2 |
Porovná všechny symboly pojmenované buď MyType1 nebo MyType2 . |
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS.MyType.MyMethod(ParamType) |
Odpovídá konkrétní metodě MyMethod se zadaným plně kvalifikovaným podpisem. |
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS1.MyType1.MyMethod1(ParamType)|M:NS2.MyType2.MyMethod2(ParamType) |
Odpovídá konkrétním metodám MyMethod1 a MyMethod2 příslušným plně kvalifikovaným podpisům. |
Vyloučení konkrétních typů a jejich odvozených typů
Z analýzy můžete vyloučit konkrétní typy a jejich odvozené typy. Pokud chcete například určit, že pravidlo by se nemělo spouštět u žádné metody v rámci pojmenovaných MyType
typů a jejich odvozených typů, přidejte do souboru .editorconfig v projektu následující dvojici klíč-hodnota:
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType
Povolené formáty názvů symbolů v hodnotě možnosti (oddělené ):|
- Pouze název typu (zahrnuje všechny typy s názvem bez ohledu na typ nebo obor názvů).
- Plně kvalifikované názvy ve formátu ID dokumentace symbolu s volitelnou
T:
předponou.
Příklady:
Hodnota možnosti | Shrnutí |
---|---|
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType |
Odpovídá všem pojmenovaným MyType typům a všem jejich odvozeným typům. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType1|MyType2 |
Odpovídá všem typům pojmenovaným buď MyType1 nebo MyType2 a všem jejich odvozeným typům. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS.MyType |
Odpovídá určitému typu MyType s daným plně kvalifikovaným názvem a všemi jeho odvozenými typy. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS1.MyType1|M:NS2.MyType2 |
Odpovídá konkrétním typům MyType1 a MyType2 příslušným plně kvalifikovaným názvům a všem jejich odvozeným typům. |
Příklady pseudokódu
Porušení 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
Řešení 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
Porušení 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
Řešení 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