CA2312: Assicurarsi che NetDataContractSerializer.Binder sia impostato prima della deserializzazione
Proprietà | valore |
---|---|
ID regola | CA2312 |
Title | Assicurarsi di impostare NetDataContractSerializer.Binder prima della deserializzazione |
Categoria | Sicurezza |
La correzione causa un'interruzione o meno | Non causa un'interruzione |
Abilitato per impostazione predefinita in .NET 9 | No |
Causa
È stato chiamato o fatto riferimento a un System.Runtime.Serialization.NetDataContractSerializer metodo di deserializzazione e la Binder proprietà può essere Null.
Questa regola è simile a CA2311, ma l'analisi non è in grado di determinare se è Binder sicuramente Null.
Per impostazione predefinita, questa regola analizza l'intera codebase, ma è configurabile.
Avviso
La limitazione dei tipi con serializationBinder non può impedire tutti gli attacchi. Per altre informazioni, vedere la guida alla sicurezza BinaryFormatter.
Descrizione regola
I deserializzatori non sicuri sono vulnerabili durante la deserializzazione dei dati non attendibili. Un utente malintenzionato potrebbe modificare i dati serializzati in modo da includere tipi imprevisti per inserire oggetti con effetti collaterali dannosi. Un attacco a un deserializzatore non sicuro potrebbe, ad esempio, eseguire comandi nel sistema operativo sottostante, comunicare in rete o eliminare file.
Questa regola trova System.Runtime.Serialization.NetDataContractSerializer chiamate o riferimenti al metodo di deserializzazione quando potrebbe Binder essere Null. Se si vuole impedire la deserializzazione indipendentemente NetDataContractSerializer dalla Binder proprietà , disabilitare questa regola e CA2311 e abilitare la regola CA2310.
NetDataContractSerializer
non è sicuro e non può essere reso sicuro. Per altre informazioni, vedere la guida alla sicurezza BinaryFormatter.
Come correggere le violazioni
- Usare invece un serializzatore sicuro e non consentire a un utente malintenzionato di specificare un tipo arbitrario da deserializzare. Per altre informazioni, vedere Alternative preferite.
- Rendere i dati serializzati a prova di manomissione. Dopo la serializzazione, firmare in modo crittografico i dati serializzati. Prima della deserializzazione, convalidare la firma crittografica. Proteggere la chiave crittografica dalla divulgazione e dalla progettazione per le rotazioni delle chiavi.
- Questa opzione rende il codice vulnerabile agli attacchi Denial of Service e ai possibili attacchi di esecuzione del codice remoto in futuro. Per altre informazioni, vedere la guida alla sicurezza BinaryFormatter. Limitare i tipi deserializzati. Implementare un oggetto personalizzato System.Runtime.Serialization.SerializationBinder. Prima di deserializzare, impostare la proprietà su un'istanza
Binder
del personalizzato SerializationBinder in tutti i percorsi di codice. Nel metodo sottoposto BindToType a override, se il tipo è imprevisto, generare un'eccezione per arrestare la deserializzazione.
Quando eliminare gli avvisi
NetDataContractSerializer
non è sicuro e non può essere reso sicuro.
Configurare il codice da analizzare
Usare le opzioni seguenti per configurare le parti della codebase in cui eseguire questa regola.
È possibile configurare queste opzioni solo per questa regola, per tutte le regole a cui si applica o per tutte le regole in questa categoria (Sicurezza) a cui si applica. Per altre informazioni, vedere Opzioni di configurazione delle regole di qualità del codice.
Escludere simboli specifici
È possibile escludere simboli specifici, ad esempio tipi e metodi, dall'analisi. Ad esempio, per specificare che la regola non deve essere eseguita in alcun codice all'interno di tipi denominati MyType
, aggiungere la coppia chiave-valore seguente a un file con estensione editorconfig nel progetto:
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType
Formati di nome simbolo consentiti nel valore dell'opzione (separati da |
):
- Solo nome simbolo (include tutti i simboli con il nome, indipendentemente dal tipo o dallo spazio dei nomi contenitore).
- Nomi completi nel formato ID della documentazione del simbolo. Ogni nome di simbolo richiede un prefisso di tipo simbolo, ad esempio
M:
per i metodi,T:
per i tipi eN:
per gli spazi dei nomi. .ctor
per costruttori e.cctor
per costruttori statici.
Esempi:
Valore opzione | Riepilogo |
---|---|
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType |
Corrisponde a tutti i simboli denominati MyType . |
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType1|MyType2 |
Corrisponde a tutti i simboli denominati MyType1 o MyType2 . |
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS.MyType.MyMethod(ParamType) |
Corrisponde a un metodo MyMethod specifico con la firma completa specificata. |
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS1.MyType1.MyMethod1(ParamType)|M:NS2.MyType2.MyMethod2(ParamType) |
Trova la corrispondenza con metodi MyMethod1 specifici e MyMethod2 con le rispettive firme complete. |
Escludere tipi specifici e i relativi tipi derivati
È possibile escludere tipi specifici e i relativi tipi derivati dall'analisi. Ad esempio, per specificare che la regola non deve essere eseguita in alcun metodo all'interno di tipi denominati MyType
e dei relativi tipi derivati, aggiungere la coppia chiave-valore seguente a un file con estensione editorconfig nel progetto:
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType
Formati di nome simbolo consentiti nel valore dell'opzione (separati da |
):
- Solo nome di tipo (include tutti i tipi con il nome, indipendentemente dal tipo o dallo spazio dei nomi contenitore).
- Nomi completi nel formato ID della documentazione del simbolo, con un prefisso facoltativo
T:
.
Esempi:
Valore opzione | Riepilogo |
---|---|
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType |
Corrisponde a tutti i tipi denominati MyType e a tutti i relativi tipi derivati. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType1|MyType2 |
Corrisponde a tutti i tipi denominati MyType1 o MyType2 e a tutti i relativi tipi derivati. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS.MyType |
Corrisponde a un tipo MyType specifico con il nome completo specificato e tutti i relativi tipi derivati. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS1.MyType1|M:NS2.MyType2 |
Corrisponde a tipi MyType1 specifici e MyType2 con i rispettivi nomi completi e tutti i relativi tipi derivati. |
Esempi di pseudo-codice
Violazione 1
using System;
using System.IO;
using System.Runtime.Serialization;
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));
}
}
}
[DataContract]
public class BookRecord
{
[DataMember]
public string Title { get; set; }
[DataMember]
public AisleLocation Location { get; set; }
}
[DataContract]
public class AisleLocation
{
[DataMember]
public char Aisle { get; set; }
[DataMember]
public byte Shelf { get; set; }
}
public class Binders
{
public static SerializationBinder BookRecord = new BookRecordSerializationBinder();
}
public class ExampleClass
{
public BookRecord DeserializeBookRecord(byte[] bytes)
{
NetDataContractSerializer serializer = new NetDataContractSerializer();
serializer.Binder = Binders.BookRecord;
using (MemoryStream ms = new MemoryStream(bytes))
{
return (BookRecord) serializer.Deserialize(ms);
}
}
}
Imports System
Imports System.IO
Imports System.Runtime.Serialization
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
<DataContract()>
Public Class BookRecord
<DataMember()>
Public Property Title As String
<DataMember()>
Public Property Location As AisleLocation
End Class
<DataContract()>
Public Class AisleLocation
<DataMember()>
Public Property Aisle As Char
<DataMember()>
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 serializer As NetDataContractSerializer = New NetDataContractSerializer()
serializer.Binder = Binders.BookRecord
Using ms As MemoryStream = New MemoryStream(bytes)
Return CType(serializer.Deserialize(ms), BookRecord) ' CA2312 violation
End Using
End Function
End Class
Soluzione 1
using System;
using System.IO;
using System.Runtime.Serialization;
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));
}
}
}
[DataContract]
public class BookRecord
{
[DataMember]
public string Title { get; set; }
[DataMember]
public AisleLocation Location { get; set; }
}
[DataContract]
public class AisleLocation
{
[DataMember]
public char Aisle { get; set; }
[DataMember]
public byte Shelf { get; set; }
}
public class Binders
{
public static SerializationBinder BookRecord = new BookRecordSerializationBinder();
}
public class ExampleClass
{
public BookRecord DeserializeBookRecord(byte[] bytes)
{
NetDataContractSerializer serializer = new NetDataContractSerializer();
// Ensure that Binder is always non-null before deserializing
serializer.Binder = Binders.BookRecord ?? throw new Exception("Expected non-null");
using (MemoryStream ms = new MemoryStream(bytes))
{
return (BookRecord) serializer.Deserialize(ms);
}
}
}
Imports System
Imports System.IO
Imports System.Runtime.Serialization
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
<DataContract()>
Public Class BookRecord
<DataMember()>
Public Property Title As String
<DataMember()>
Public Property Location As AisleLocation
End Class
<DataContract()>
Public Class AisleLocation
<DataMember()>
Public Property Aisle As Char
<DataMember()>
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 serializer As NetDataContractSerializer = New NetDataContractSerializer()
' Ensure that Binder is always non-null before deserializing
serializer.Binder = If(Binders.BookRecord, New Exception("Expected non-null"))
Using ms As MemoryStream = New MemoryStream(bytes)
Return CType(serializer.Deserialize(ms), BookRecord)
End Using
End Function
End Class
Violazione 2
using System;
using System.IO;
using System.Runtime.Serialization;
[DataContract]
public class BookRecord
{
[DataMember]
public string Title { get; set; }
[DataMember]
public string Author { get; set; }
[DataMember]
public int PageCount { get; set; }
[DataMember]
public AisleLocation Location { get; set; }
}
[DataContract]
public class AisleLocation
{
[DataMember]
public char Aisle { get; set; }
[DataMember]
public byte Shelf { get; set; }
}
public class ExampleClass
{
public NetDataContractSerializer Serializer { get; set; }
public BookRecord DeserializeBookRecord(byte[] bytes)
{
using (MemoryStream ms = new MemoryStream(bytes))
{
return (BookRecord) this.Serializer.Deserialize(ms); // CA2312 violation
}
}
}
Imports System
Imports System.IO
Imports System.Runtime.Serialization
<DataContract()>
Public Class BookRecord
<DataMember()>
Public Property Title As String
<DataMember()>
Public Property Author As String
<DataMember()>
Public Property Location As AisleLocation
End Class
<DataContract()>
Public Class AisleLocation
<DataMember()>
Public Property Aisle As Char
<DataMember()>
Public Property Shelf As Byte
End Class
Public Class ExampleClass
Public Property Serializer As NetDataContractSerializer
Public Function DeserializeBookRecord(bytes As Byte()) As BookRecord
Using ms As MemoryStream = New MemoryStream(bytes)
Return CType(Me.Serializer.Deserialize(ms), BookRecord) ' CA2312 violation
End Using
End Function
End Class
Soluzione 2
using System;
using System.IO;
using System.Runtime.Serialization;
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));
}
}
}
[DataContract]
public class BookRecord
{
[DataMember]
public string Title { get; set; }
[DataMember]
public string Author { get; set; }
[DataMember]
public int PageCount { get; set; }
[DataMember]
public AisleLocation Location { get; set; }
}
[DataContract]
public class AisleLocation
{
[DataMember]
public char Aisle { get; set; }
[DataMember]
public byte Shelf { get; set; }
}
public class ExampleClass
{
public BookRecord DeserializeBookRecord(byte[] bytes)
{
NetDataContractSerializer serializer = new NetDataContractSerializer();
serializer.Binder = new BookRecordSerializationBinder();
using (MemoryStream ms = new MemoryStream(bytes))
{
return (BookRecord) serializer.Deserialize(ms);
}
}
}
Imports System
Imports System.IO
Imports System.Runtime.Serialization
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
<DataContract()>
Public Class BookRecord
<DataMember()>
Public Property Title As String
<DataMember()>
Public Property Author As String
<DataMember()>
Public Property Location As AisleLocation
End Class
<DataContract()>
Public Class AisleLocation
<DataMember()>
Public Property Aisle As Char
<DataMember()>
Public Property Shelf As Byte
End Class
Public Class ExampleClass
Public Function DeserializeBookRecord(bytes As Byte()) As BookRecord
Dim serializer As NetDataContractSerializer = New NetDataContractSerializer()
serializer.Binder = New BookRecordSerializationBinder()
Using ms As MemoryStream = New MemoryStream(bytes)
Return CType(serializer.Deserialize(ms), BookRecord)
End Using
End Function
End Class