Cyber Security – BinaryFormatter: Um Risco à Segurança
O código fonte do .NET está em constante evolução e sua equipe de desenvolvimento está atenta as questões de Cyber Security, no entanto, classes legadas como o BinaryFormatter continuam a apresentar vulnerabilidades exploráveis por atacantes. Nesta análise, discutiremos a vulnerabilidade crítica associada ao BinaryFormatter registrada pelos códigos CVE-2023-32737, CWE-502, e CA2300 (você pode ler mais nos links), destacando o que são esses problemas, como eles impactam a segurança, e as melhores práticas para mitigá-los.
O que é o BinaryFormatter?
O BinaryFormatter é uma classe do .NET Framework utilizada para serializar e desserializar objetos em formato binário, facilitando o armazenamento ou a transferência de dados complexos. No entanto, devido à forma como o BinaryFormatter trata dados durante a desserialização, ele pode ser suscetível a ataques de desserialização inseguros, onde entradas maliciosas podem executar códigos arbitrários e comprometer a segurança da aplicação.
Cyber Security – Entendendo os Códigos de Vulnerabilidade
CVE-2023-32737: Código de Vulnerabilidade Comum
O CVE-2023-32737 é um identificador específico para uma vulnerabilidade do tipo “desserialização insegura” encontrada no BinaryFormatter. Ele indica que a manipulação de dados serializados possibilita a exploração da classe, permitindo que códigos realizem ações inesperadas e potencialmente maliciosas no ambiente de execução da aplicação.
CWE-502: Categoria de Fraquezas
O CWE-502 refere-se à categoria “Desserialização de Dados Não Confiáveis”. Essa classificação indica que uma vulnerabilidade ocorre quando dados maliciosos são desserializados, o que pode desencadear execuções de código indesejadas. Em outras palavras, o processamento de dados de entrada potencialmente perigosos pode ameaçar a segurança do sistema e comprometer sua integridade.
CA2300: Análise de Código para Segurança
O CA2300 recomenda evitar o processamento direto de dados não confiáveis, garantindo maior segurança no sistema. Esse aviso serve para alertar desenvolvedores durante o processo de construção do software, sinalizando o uso de práticas inseguras, como a desserialização direta de dados de fontes desconhecidas.
Impacto da Vulnerabilidade do BinaryFormatter
Ao utilizar o BinaryFormatter, aplicações correm o risco de receber objetos binários maliciosos que, durante a desserialização, podem executar código indesejado. Essa vulnerabilidade representa uma séria ameaça, pois permite a elevação de privilégios ou a execução de comandos remotamente, comprometendo a integridade do sistema.
Por ser uma biblioteca amplamente utilizada e inclusa no .NET Framework (não confundir com .NET Core, onde o uso do BinaryFormatter já é desaconselhado e possui suporte limitado), muitos sistemas podem ser alvos potenciais, especialmente os que interagem com dados de fontes externas.
Cyber Security – Quatro formas de mitigar o problema do BinaryFormatter
1. Substituindo o BinaryFormatter
- A Microsoft já recomenda que o BinaryFormatter seja evitado em novos projetos, incentivando o uso de alternativas mais seguras, como o System.Text.Json, XmlSerializer, ou DataContractSerializer.
2. Verificar a Origem dos Dados
- Garanta que dados serializados são provenientes de fontes confiáveis. Mesmo ao utilizar métodos alternativos de serialização, é importante controlar e garantir a confiabilidade da origem dos dados.
3. Cyber Security – Atualizar o .NET e Aplicar Patches de Segurança
- A Microsoft lança periodicamente atualizações e patches para corrigir vulnerabilidades. Assegure-se de que o ambiente de desenvolvimento e os aplicativos estejam com as versões mais recentes do .NET Framework.
4. Realizar Análise Estática do Código
- Ferramentas de análise estática, como o Code Analysis for .NET (que fornece o alerta CA2300), podem identificar o uso de BinaryFormatter e sugerir mudanças antes da implantação da aplicação.
Alternativas Seguras para Serialização
Como parte das melhores práticas, os desenvolvedores podem considerar o uso de serializadores seguros e específicos para os dados e cenários em questão. Algumas das alternativas recomendadas incluem:
- System.Text.Json: Uma alternativa leve e segura para a serialização JSON.
- DataContractSerializer: Indicado para cenários de comunicação entre serviços, pois oferece mais controle sobre o que é serializado.
- Protobuf: Uma alternativa altamente eficiente e segura, principalmente para comunicação entre microserviços.
- NrbfDecoder: Uma alternativa voltada para a leitura e interpretação de objetos binários que mantém compatibilidade com o BinaryFormatter. É usada para decodificar o formato NRBF (.NET Remoting Binary Format), que permite manipular dados binários sem os riscos de execução de código presentes no BinaryFormatter. Embora não seja uma substituição direta, o NrbfDecoder pode ajudar a migrar dados legados ou analisar binários com segurança. Saiba mais sobre o NrbfDecoder no site da Microsoft.
Cyber Security – Substituindo o BinaryFormatter com o NrbfDecoder
Imagine o cenário onde recebemos via API, dados formatados usando o BinaryFormatter, ou seja, não temos domínio sobre o client mas apenas da API que deserializa esses dados tambem usando o BinaryFormatter.
Este caso categoriza o problema de segurança pois podemos receber um código malicioso entre esses dados. Como podemos resolver nosso lado sem quebrar o contrato com os consumidores de nossas APIs?
Uma opção é usar o NrbfDecoder, uma biblioteca disponível no NuGet. Na data de escrita deste artigo, ela ainda permanece em Release Candidate, embora a Microsoft já a considere em “produção”. Isso ocorre porque sua API ainda deve passar por uma grande atualização.
Vamos explorar abaixo uma solução de desserialização com o NrbfDecoder mencionado anteriormente.
Considere que a classe abaixo foi serializada com BinaryFormatter e recebemos uma MemoryStream contendo esta classe.
public class Employee
{
public int Id { get; set; }
public List<string> Roles { get; set; }
}
Vamos ao codigo que desserializa:
...
// Valida se a MemoryStream pode ser desserializada
if (NrbfDecoder.StartsWithPayloadHeader(memoryStream))
{
memoryStream.Position = 0;
// Decodifica a instancia de uma classe que não seja um Array ou tipo primitivo
ClassRecord decodedClass = NrbfDecoder.DecodeClassRecord(memoryStream);
// Iterando sobre as propriedades para fazer bind pelo nome
foreach (var memberName in decodedClass.MemberNames)
{
if (memberName.Equals(nameof(employee.Id))
{
// Lidando com tipos primitivos
employee.Id = decodedClass.GetInt32(memberName);
}
if (memberName.Equals(nameof(employee.Roles))
{
var complexDecoded = decodedClass.GetClassRecord(memberName);
// Identifico o tipo para trata-lo corretamente
if (complexDecoded.TypeName.FullName.Contains("List[[System.String]]"))
{
var listDecoded = complexDecoded.GetArrayRecord("_items")
.GetArray(expectedArrayType: typeof(string));
foreach (var item in listDecoded)
{
// Se for tipo primitivo
if (item is not ClassRecord)
{
employee.Roles.Add(item);
}
// Caso não seja tipo primitivo aqui seguimos decodificando as
// classes ou arrays conforme fizemos anteriormente.
}
}
}
}
// Ao final temos uma instancia da classe Employee desserializada
Conclusão
Embora o BinaryFormatter seja uma ferramenta poderosa no .NET, ele se tornou uma fonte de risco devido à sua suscetibilidade à desserialização insegura, dessa forma a vulnerabilidade identificada pelo CVE-2023-32737 e categorizada em CWE-502 destaca a necessidade de adotar práticas seguras de serialização e controle de dados. Por isso, a Microsoft e a comunidade .NET recomendam substituir o BinaryFormatter por métodos de serialização mais seguros, protegendo assim as aplicações e prevenindo que explorações comprometam a integridade do sistema.