Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Atenção
BinaryFormatter O suporte não é recomendado. Use-o apenas como uma ponte de migração temporária para aplicações legadas que não podem migrar imediatamente para as novas APIs seguras em termos de tipo. Esta abordagem comporta riscos de segurança significativos.
Este artigo mostra como configurar um suporte limitado BinaryFormatter para operações da área de transferência do Windows Forms no .NET 10. Embora BinaryFormatter tenha sido removido do tempo de execução no .NET 9 devido a vulnerabilidades de segurança, restaure a funcionalidade limitada por meio de configuração explícita para aplicativos herdados que precisam de tempo para migrar.
Para obter orientações completas para migração para as novas APIs com segurança de tipos, consulte Área de transferência do Windows Forms e alterações no DataObject no .NET 10.
Importante
Este conteúdo aplica-se apenas ao .NET moderno e não ao .NET Framework, salvo indicação em contrário.
Pré-requisitos
Antes de continuar, analise estes conceitos:
- Como é que o seu aplicativo usa
BinaryFormatteratualmente em operações da área de transferência. - As vulnerabilidades de segurança que levaram à remoção do
BinaryFormatter. - O seu cronograma de migração para as novas APIs de transferência segura de tipos.
Para obter mais informações, consulte estes artigos:
- Riscos de desserialização no uso de BinaryFormatter e tipos relacionados
- Guia de migração BinaryFormatter
Avisos e riscos de segurança
BinaryFormatter é inerentemente insegura e preterida pelos seguintes motivos:
- Vulnerabilidades de execução arbitrária de código: os invasores podem executar código mal-intencionado durante a desserialização, expondo seu aplicativo a ataques remotos.
- Ataques de negação de serviço: dados mal-intencionados da área de transferência podem consumir em excesso memória ou recursos de CPU, causando falhas no sistema ou instabilidade.
- Riscos de divulgação de informações: os invasores podem extrair dados confidenciais da memória.
- Sem limites de segurança: o formato é fundamentalmente inseguro e as definições de configuração não podem protegê-lo.
Habilite esse suporte apenas como uma ponte temporária enquanto atualiza seu aplicativo para usar as novas APIs seguras para tipos.
Instalar o pacote de compatibilidade
Adicione o pacote de compatibilidade não suportado BinaryFormatter ao seu projeto. Este pacote fornece o suporte de tempo de execução necessário para BinaryFormatter operações:
<ItemGroup>
<PackageReference Include="System.Runtime.Serialization.Formatters" Version="10.0.0*-*"/>
</ItemGroup>
Observação
Este pacote está marcado como não suportado e preterido. Use-o apenas para compatibilidade temporária durante a migração.
Habilitar a serialização insegura em seu projeto
Defina a EnableUnsafeBinaryFormatterSerialization propriedade como true em seu arquivo de projeto. Esta propriedade instrui o compilador a permitir o uso de BinaryFormatter.
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryFormatterSerialization>
</PropertyGroup>
Sem essa configuração, seu aplicativo gera erros de compilação quando tenta usar BinaryFormatter APIs.
Configurar a opção de tempo de execução do Windows Forms
Crie ou atualize o arquivo runtimeconfig.json do seu aplicativo para habilitar a opção de área de transferência específica para o Windows Forms. Esta configuração permite que as operações da área de transferência recaiam para BinaryFormatter quando necessário:
{
"runtimeOptions": {
"configProperties": {
"Windows.ClipboardDragDrop.EnableUnsafeBinaryFormatterSerialization": true
}
}
}
Importante
Sem essa opção específica de tempo de execução, as operações da área de transferência não terão como alternativa o recurso BinaryFormatter, mesmo que o suporte geral à serialização esteja habilitado. Essa opção é necessária especificamente para a funcionalidade do Windows Forms e da área de transferência do WPF.
Implementar resolvedores de tipo focados na segurança
Mesmo com BinaryFormatter habilitado, implemente resolvedores de tipo para restringir a desserialização a tipos explicitamente aprovados. Os resolvedores de tipos fornecem sua única defesa contra ataques mal-intencionados de carga útil.
Criar um resolvedor de tipo seguro
// Create a security-focused type resolver
private static Type SecureTypeResolver(TypeName typeName)
{
// Explicit allow-list of permitted types—add only what you need
var allowedTypes = new Dictionary<string, Type>
{
["MyApp.Person"] = typeof(Person),
["MyApp.AppSettings"] = typeof(AppSettings),
["System.String"] = typeof(string),
["System.Int32"] = typeof(int),
// Add only the specific types your application requires
};
// Only allow explicitly listed types - exact string match required
if (allowedTypes.TryGetValue(typeName.FullName, out Type allowedType))
{
return allowedType;
}
// Reject any type not in the allow-list with clear error message
throw new InvalidOperationException(
$"Type '{typeName.FullName}' is not permitted for clipboard deserialization");
}
' Create a security-focused type resolver
Private Shared Function SecureTypeResolver(typeName As TypeName) As Type
' Explicit allow-list of permitted types—add only what you need
Dim allowedTypes As New Dictionary(Of String, Type) From {
{"MyApp.Person", GetType(Person)},
{"MyApp.AppSettings", GetType(AppSettings)},
{"System.String", GetType(String)},
{"System.Int32", GetType(Integer)}
} ' Add only the specific types your application requires
' Only allow explicitly listed types - exact string match required
Dim allowedType As Type = Nothing
If allowedTypes.TryGetValue(typeName.FullName, allowedType) Then
Return allowedType
End If
' Reject any type not in the allow-list with clear error message
Throw New InvalidOperationException(
$"Type '{typeName.FullName}' is not permitted for clipboard deserialization")
End Function
Usar o resolvedor de tipos com operações da área de transferência
// Use the resolver with clipboard operations
private static Type SecureTypeResolver(TypeName typeName)
{
// Implementation from SecureTypeResolver example
// ... (allow-list implementation here)
throw new InvalidOperationException($"Type '{typeName.FullName}' is not permitted");
}
public static void UseSecureTypeResolver()
{
// Retrieve legacy data using the secure type resolver
if (Clipboard.TryGetData("LegacyData", SecureTypeResolver, out MyCustomType data))
{
ProcessLegacyData(data);
}
else
{
Console.WriteLine("No compatible data found on clipboard");
}
}
' Use the resolver with clipboard operations
Private Shared Function SecureTypeResolver(typeName As TypeName) As Type
' Implementation from SecureTypeResolver example
' ... (allow-list implementation here)
Throw New InvalidOperationException($"Type '{typeName.FullName}' is not permitted")
End Function
Public Shared Sub UseSecureTypeResolver()
' Retrieve legacy data using the secure type resolver
Dim data As MyCustomType = Nothing
If Clipboard.TryGetData("LegacyData", AddressOf SecureTypeResolver, data) Then
ProcessLegacyData(data)
Else
Console.WriteLine("No compatible data found on clipboard")
End If
End Sub
Diretrizes de segurança para resolvedores de tipo
Siga estas diretrizes de segurança essenciais ao implementar resolvedores de tipo:
Usar listas de permissões explícitas
- Rejeitar por padrão: permita apenas tipos explicitamente listados.
- Sem curingas: evite correspondência de padrões ou permissões baseadas em namespace.
- Correspondência exata: requira correspondências exatas de cadeias de caracteres para nomes de tipos.
Validar todas as entradas
- Validação do nome do tipo: certifique-se de que os nomes dos tipos correspondam aos formatos esperados.
- Restrições de assembly: Limite tipos a assemblies que sejam conhecidos e confiáveis.
- Verificação de versão: considere restrições de tipo específicas da versão.
Lide com tipos desconhecidos com segurança
- Lançar exceções: sempre lance para tipos não autorizados.
- Registrar tentativas: Considere registrar tentativas de acesso não autorizado.
- Tornar claras as mensagens de erro: ofereça motivos específicos de rejeição para depuração.
Manutenção regular
- Auditar regularmente: revise e atualize a lista de tipos permitidos.
- Remover tipos não utilizados: elimine permissões para tipos que não são mais necessários.
- Decisões documentais: Mantenha uma documentação clara do motivo pelo qual cada tipo é permitido.
Teste sua configuração
Depois de configurar BinaryFormatter o suporte, teste seu aplicativo para garantir que ele funcione corretamente:
- Verificar as operações da área de transferência: teste o armazenamento e a recuperação de dados com seus tipos personalizados.
- Resolvedor de tipos de teste: confirme se os tipos não autorizados foram rejeitados corretamente.
- Monitorize a segurança: esteja atento a quaisquer tentativas inesperadas de resolução de tipos.
- Teste de desempenho: certifique-se de que o resolvedor de tipo não afeta significativamente o desempenho.
public static void TestBinaryFormatterConfiguration()
{
// Test data to verify configuration
var testPerson = new Person { Name = "Test User", Age = 30 };
try
{
// Test storing data (this should work with proper configuration)
Clipboard.SetData("TestPerson", testPerson);
Console.WriteLine("Successfully stored test data on clipboard");
// Test retrieving with type resolver
if (Clipboard.TryGetData("TestPerson", SecureTypeResolver, out Person retrievedPerson))
{
Console.WriteLine($"Successfully retrieved: {retrievedPerson.Name}, Age: {retrievedPerson.Age}");
}
else
{
Console.WriteLine("Failed to retrieve test data");
}
// Test that unauthorized types are rejected
try
{
Clipboard.TryGetData("TestPerson", UnauthorizedTypeResolver, out Person _);
Console.WriteLine("ERROR: Unauthorized type was not rejected!");
}
catch (InvalidOperationException ex)
{
Console.WriteLine($"SUCCESS: Unauthorized type properly rejected - {ex.Message}");
}
}
catch (Exception ex)
{
Console.WriteLine($"Configuration test failed: {ex.Message}");
}
}
private static Type SecureTypeResolver(TypeName typeName)
{
var allowedTypes = new Dictionary<string, Type>
{
["ClipboardExamples.Person"] = typeof(Person),
};
if (allowedTypes.TryGetValue(typeName.FullName, out Type allowedType))
{
return allowedType;
}
throw new InvalidOperationException($"Type '{typeName.FullName}' is not permitted");
}
private static Type UnauthorizedTypeResolver(TypeName typeName)
{
// Intentionally restrictive resolver to test rejection
throw new InvalidOperationException($"No types are permitted by this test resolver");
}
Public Shared Sub TestBinaryFormatterConfiguration()
' Test data to verify configuration
Dim testPerson As New Person With {.Name = "Test User", .Age = 30}
Try
' Test storing data (this should work with proper configuration)
Clipboard.SetData("TestPerson", testPerson)
Console.WriteLine("Successfully stored test data on clipboard")
' Test retrieving with type resolver
Dim retrievedPerson As Person = Nothing
If Clipboard.TryGetData("TestPerson", AddressOf SecureTypeResolver, retrievedPerson) Then
Console.WriteLine($"Successfully retrieved: {retrievedPerson.Name}, Age: {retrievedPerson.Age}")
Else
Console.WriteLine("Failed to retrieve test data")
End If
' Test that unauthorized types are rejected
Try
Dim testResult As Person = Nothing
Clipboard.TryGetData("TestPerson", AddressOf UnauthorizedTypeResolver, testResult)
Console.WriteLine("ERROR: Unauthorized type was not rejected!")
Catch ex As InvalidOperationException
Console.WriteLine($"SUCCESS: Unauthorized type properly rejected - {ex.Message}")
End Try
Catch ex As Exception
Console.WriteLine($"Configuration test failed: {ex.Message}")
End Try
End Sub
Private Shared Function SecureTypeResolver(typeName As TypeName) As Type
Dim allowedTypes As New Dictionary(Of String, Type) From {
{"ClipboardExamples.Person", GetType(Person)}
}
Dim allowedType As Type = Nothing
If allowedTypes.TryGetValue(typeName.FullName, allowedType) Then
Return allowedType
End If
Throw New InvalidOperationException($"Type '{typeName.FullName}' is not permitted")
End Function
Private Shared Function UnauthorizedTypeResolver(typeName As TypeName) As Type
' Intentionally restrictive resolver to test rejection
Throw New InvalidOperationException($"No types are permitted by this test resolver")
End Function
Planeie a sua estratégia de migração
Embora BinaryFormatter o suporte forneça compatibilidade temporária, desenvolva um plano de migração para migrar para as novas APIs seguras para tipos:
- Identificar uso: catalogar todas as operações da área de transferência usando tipos personalizados.
- Priorize a migração: concentre-se primeiro nas operações mais sensíveis à segurança.
- Atualizar incrementalmente: migre uma operação de cada vez para reduzir o risco.
- Teste minuciosamente: Garanta que novas implementações forneçam funcionalidade equivalente.
- Remover BinaryFormatter: desative o suporte assim que a migração for concluída.
Limpeza de recursos
Depois de migrar para as novas APIs de área de transferência seguras, do tipo seguro, remova a configuração BinaryFormatter para melhorar a segurança.
- Remova a referência de pacote
System.Runtime.Serialization.Formatters. - Remova a
EnableUnsafeBinaryFormatterSerializationpropriedade do arquivo de projeto. - Remova a definição
Windows.ClipboardDragDrop.EnableUnsafeBinaryFormatterSerializationdo seuruntimeconfig.json. - Exclua implementações de resolvedor de tipo que não são mais necessárias.
Conteúdo relacionado
.NET Desktop feedback