Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Cuidado
BinaryFormatter O suporte não é recomendado. Use apenas como uma ponte de migração temporária para aplicativos legados que não podem migrar imediatamente para as novas APIs seguras por tipo. Essa abordagem traz riscos significativos de segurança.
Este artigo mostra como configurar o suporte limitado BinaryFormatter para operações de área de transferência do Windows Forms no .NET 10. Embora BinaryFormatter tenha sido removido do runtime no .NET 9 devido a vulnerabilidades de segurança, restaure uma funcionalidade limitada por meio de configuração explícita para aplicativos legados que precisam de tempo para migrar.
Para obter diretrizes de migração completas para as novas APIs de tipos seguros, consulte alterações no DataObject e na área de transferência do Windows Forms no .NET 10.
Importante
Esse conteúdo só se aplica ao .NET moderno e não ao .NET Framework, a menos que especificado de outra forma.
Pré-requisitos
Antes de continuar, examine estes conceitos:
- Como seu aplicativo usa
BinaryFormatteratualmente em operações de área de transferência. - As vulnerabilidades de segurança que levaram à remoção de
BinaryFormatter. - Sua linha do tempo de migração para as novas APIs de área de transferência com segurança de tipo.
Para obter mais informações, consulte estes artigos:
- Riscos de desserialização no uso de BinaryFormatter e tipos relacionados
- Guia de migração do BinaryFormatter
Avisos e riscos de segurança
BinaryFormatter é inerentemente inseguro e preterido por estes motivos:
- Vulnerabilidades arbitrárias de execução 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 maliciosos na área de transferência podem consumir memória excessiva ou recursos de CPU, levando a falhas 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 configurações não podem protegê-lo.
Habilite esse suporte apenas como uma ponte temporária enquanto você atualiza seu aplicativo para usar as novas APIs com segurança de tipo.
Instalar o pacote de compatibilidade
Adicione o pacote de compatibilidade não suportado BinaryFormatter ao seu projeto. Este pacote fornece o suporte de runtime necessário para BinaryFormatter operações:
<ItemGroup>
<PackageReference Include="System.Runtime.Serialization.Formatters" Version="10.0.0*-*"/>
</ItemGroup>
Observação
Esse pacote é marcado como sem suporte e preterido. Use-o apenas para compatibilidade temporária durante a migração.
Habilitar a serialização não segura em seu projeto
Defina a propriedade EnableUnsafeBinaryFormatterSerialization para true no arquivo de projeto. Essa propriedade informa ao compilador para 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 o comutador de runtime 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 do Windows Forms. Esta configuração permite que as operações de área de transferência revertam para BinaryFormatter quando necessário.
{
"runtimeOptions": {
"configProperties": {
"Windows.ClipboardDragDrop.EnableUnsafeBinaryFormatterSerialization": true
}
}
}
Importante
Sem esse comutador específico de runtime, as operações de área de transferência não serão revertidas para BinaryFormatter, mesmo se o suporte geral de serialização estiver habilitado. Essa opção é necessária especificamente para a funcionalidade de área de transferência do Windows Forms e do WPF.
Implementar resolutores de tipos com foco na segurança
Mesmo com BinaryFormatter habilitado, implemente resolvedores de tipo para restringir a desserialização a tipos explicitamente aprovados. Os resolvedores de tipo fornecem a única defesa disponível contra ataques de carga maliciosa.
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 de á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: permitir apenas tipos explicitamente listados.
- Sem curingas: evite a correspondência de padrões ou permissões baseadas em namespace.
- Correspondência exata: exigir correspondências exatas de cadeia de caracteres para nomes de tipo.
Validar todas as entradas
- Validação de nome de tipo: verifique se os nomes de tipo correspondem aos formatos esperados.
- Restrições de assembly: Limitar tipos a assemblies conhecidos e confiáveis.
- Verificação de versão: considere restrições de tipo específicas de versão.
Manipular tipos desconhecidos com segurança
- Lançar exceções: sempre lançar para tipos não autorizados.
- Tentativas de registro: considere registrar tentativas de acesso não autorizado.
- Mensagens de erro claras: forneça motivos específicos de rejeição para depuração.
Manutenção regular
- Audite regularmente: examine e atualize a lista de tipos permitidos.
- Remover tipos não utilizados: eliminar permissões para tipos que não são mais necessários.
- Decisões de documento: mantenha uma documentação clara do motivo pelo qual cada tipo é permitido.
Testar sua configuração
Depois de configurar o BinaryFormatter suporte, teste seu aplicativo para garantir que ele funcione corretamente:
- Verificar operações de área de transferência: testar o armazenamento e a recuperação de dados com os seus tipos personalizados.
- Resolvedor de tipo de teste: confirme se os tipos não autorizados foram corretamente rejeitados.
- Monitorar a segurança: observe todas as tentativas inesperadas de resolução de tipo.
- Teste de desempenho: verifique se o resolvedor de tipos 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
Planejar sua estratégia de migração
Embora BinaryFormatter o suporte forneça compatibilidade temporária, desenvolva um plano de migração para as novas APIs com segurança de tipos.
- Identificar o uso: cataloge todas as operações de área de transferência usando tipos personalizados.
- Priorizar a migração: concentre-se nas operações mais sensíveis à segurança primeiro.
- Atualizar incrementalmente: migre uma operação de cada vez para reduzir o risco.
- Teste minuciosamente: verifique se novas implementações fornecem funcionalidade equivalente.
- Remover BinaryFormatter: desabilite o suporte após a conclusão da migração.
Limpar os recursos
Depois de migrar para as novas APIs de área de transferência 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 configuração
Windows.ClipboardDragDrop.EnableUnsafeBinaryFormatterSerializationdo seuruntimeconfig.json. - Exclua implementações de resolvedor de tipos que não são mais necessárias.
Conteúdo relacionado
.NET Desktop feedback