CA2311: Não desserializar sem definir primeiro NetDataContractSerializer.Binder
Property | Valor |
---|---|
ID da regra | CA2311 |
Título | Não desserializar sem definir primeiro NetDataContractSerializer.Binder |
Categoria | Segurança |
Correção interruptiva ou sem interrupção | Sem interrupção |
Habilitado por padrão no .NET 8 | Não |
Causa
Um método de desserialização System.Runtime.Serialization.NetDataContractSerializer foi chamado ou referenciado sem o conjunto de propriedades Binder.
Por padrão, essa regra analisa toda a base de código, mas isso é configurável.
Aviso
Restringir tipos com um SerializationBinder não previne todos os ataques. Para saber mais, confira o Guia de segurança do BinaryFormatter.
Descrição da regra
Desserializadores não seguros são vulneráveis ao desserializar dados não confiáveis. Um invasor pode modificar os dados serializados visando incluir tipos inesperados para injetar objetos com efeitos colaterais mal-intencionados. Um ataque contra um desserializador não seguro poderia, por exemplo, executar comandos no sistema operacional subjacente, realizar comunicações pela rede ou excluir arquivos.
Essa regra encontra referências ou chamadas de métodos de desserialização System.Runtime.Serialization.NetDataContractSerializer, quando NetDataContractSerializer não tem o conjunto Binder. Para desabilitar qualquer desserialização com NetDataContractSerializerindependentemente da propriedade Binder, desabilite essa regra e CA2312 e habilite a regra CA2310.
Como corrigir violações
- Use um serializador seguro como alternativa e não permita que um invasor especifique um tipo arbitrário a ser desserializado. Para saber mais, confira as Alternativas preferenciais.
- Torne os dados serializados à prova de adulteração. Após a serialização, assine criptograficamente os dados serializados. Antes da desserialização, valide a assinatura criptográfica. Proteja a chave criptográfica para impedir que ela seja divulgada e faça o design tendo em mente as rotações de chave.
- Essa opção torna o código vulnerável a ataques de negação de serviço e possíveis ataques de execução de código remoto no futuro. Para saber mais, confira o Guia de segurança do BinaryFormatter. Restrinja tipos desserializados. Implementar um System.Runtime.Serialization.SerializationBinder personalizado. Antes de desserializar, defina a propriedade
Binder
como uma instância do SerializationBinder personalizado em todos os caminhos de código. No método substituído BindToType, se o tipo for inesperado, gere uma exceção para interromper a desserialização.
Quando suprimir avisos
NetDataContractSerializer
não é seguro e não pode ser transformado em seguro.
Configurar código para analisar
Use as opções a seguir para configurar em quais partes da base de código essa regra deve ser executada.
Você pode configurar essas opções apenas para essa regra, para todas as regras às quais ela se aplica ou para todas as regras nessa categoria (Segurança) às quais ela se aplica. Para saber mais, confira Opções de configuração de regra de qualidade de código.
Excluir símbolos específicos
Você pode excluir da análise símbolos específicos, como tipos e métodos. Por exemplo, para especificar que a regra não deve ser executada em nenhum código dentro de tipos nomeados MyType
, adicione o seguinte par chave-valor a um arquivo .editorconfig no seu projeto:
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType
Formatos de nome de símbolo permitidos no valor da opção (separados por |
):
- Somente nome do símbolo (inclui todos os símbolos com o nome, independentemente do tipo ou namespace que contém).
- Nomes totalmente qualificados no formato de ID de documentação do símbolo. Cada nome de símbolo requer um prefixo do tipo símbolo, como
M:
para métodos,T:
para tipos eN:
para namespaces. .ctor
para construtores e.cctor
para construtores estáticos.
Exemplos:
Valor de Opção | Resumo |
---|---|
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType |
Corresponde a todos os símbolos nomeados MyType . |
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType1|MyType2 |
Corresponde a todos os símbolos nomeados MyType1 ou MyType2 . |
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS.MyType.MyMethod(ParamType) |
Corresponde ao método MyMethod específico com a assinatura totalmente qualificada especificada. |
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS1.MyType1.MyMethod1(ParamType)|M:NS2.MyType2.MyMethod2(ParamType) |
Corresponde aos métodos MyMethod1 e MyMethod2 específico com as assinaturas respectivas totalmente qualificadas. |
Excluir tipos específicos e seus tipos derivados
Você pode excluir tipos específicos e seus tipos derivados da análise. Por exemplo, para especificar que a regra não deve ser executada em nenhum método dentro de tipos nomeados MyType
e seus tipos derivados, adicione o seguinte par chave-valor a um arquivo .editorconfig no seu projeto:
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType
Formatos de nome de símbolo permitidos no valor da opção (separados por |
):
- Somente nome do tipo (inclui todos os tipos com o nome, independentemente do tipo ou namespace que contém).
- Nomes totalmente qualificados no formato de ID de documentação do símbolo, com um prefixo opcional
T:
.
Exemplos:
Valor de Opção | Resumo |
---|---|
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType |
Corresponde a todos os tipos nomeados MyType e todos os seus tipos derivados. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType1|MyType2 |
Corresponde a todos os tipos nomeados MyType1 ou MyType2 e todos os seus tipos derivados. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS.MyType |
Corresponde a um tipo MyType específico com determinado nome totalmente qualificado e todos os seus tipos derivados. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS1.MyType1|M:NS2.MyType2 |
Corresponde a tipos MyType1 e MyType2 específicos com os respectivos nomes totalmente qualificados e todos os seus tipos derivados. |
Exemplos de pseudocódigo
Violação
using System;
using System.IO;
using System.Runtime.Serialization;
[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 ExampleClass
{
public BookRecord DeserializeBookRecord(byte[] bytes)
{
NetDataContractSerializer serializer = new NetDataContractSerializer();
using (MemoryStream ms = new MemoryStream(bytes))
{
return (BookRecord) serializer.Deserialize(ms); // CA2311 violation
}
}
}
Imports System
Imports System.IO
Imports System.Runtime.Serialization
<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 ExampleClass
Public Function DeserializeBookRecord(bytes As Byte()) As BookRecord
Dim serializer As NetDataContractSerializer = New NetDataContractSerializer()
Using ms As MemoryStream = New MemoryStream(bytes)
Return CType(serializer.Deserialize(ms), BookRecord) ' CA2311 violation
End Using
End Function
End Class
Solução
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 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 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
Regras relacionadas
CA2310: Não usar o desserializador inseguro NetDataContractSerializer
CA2312: Verificar se NetDataContractSerializer.Binder foi definido antes de desserializar