Nota
O acceso a esta páxina require autorización. Pode tentar iniciar sesión ou modificar os directorios.
O acceso a esta páxina require autorización. Pode tentar modificar os directorios.
Precaución
BinaryFormatter No se recomienda la compatibilidad. Úselo solo como puente de migración temporal para aplicaciones heredadas que no pueden migrar inmediatamente a las nuevas API con seguridad de tipos. Este enfoque conlleva riesgos de seguridad significativos.
En este artículo se muestra cómo configurar la compatibilidad limitada BinaryFormatter con las operaciones del Portapapeles de Windows Forms en .NET 10. Aunque BinaryFormatter se quitó del entorno de ejecución en .NET 9 debido a vulnerabilidades de seguridad, restaure la funcionalidad limitada a través de la configuración explícita para las aplicaciones heredadas que necesitan tiempo de migración.
Para obtener instrucciones completas sobre la migración a las nuevas API seguras para tipos, consulte El Portapapeles de Windows Forms y los cambios de DataObject en .NET 10.
Importante
Este contenido solo se aplica a .NET moderno y no a .NET Framework, a menos que se especifique lo contrario.
Prerrequisitos
Antes de continuar, revise estos conceptos:
- Cómo usa
BinaryFormatterla aplicación actualmente en las operaciones del Portapapeles. - Vulnerabilidades de seguridad que llevaron a la eliminación de
BinaryFormatter. - Escala de tiempo de migración a las nuevas API del Portapapeles con seguridad de tipos.
Para obtener más información, consulte estos artículos:
- Riesgos de deserialización en el uso de BinaryFormatter y tipos relacionados
- Guía de migración de BinaryFormatter
Advertencias y riesgos de seguridad
BinaryFormatter es intrínsecamente inseguro y en desuso por estas razones:
- Vulnerabilidades arbitrarias de ejecución de código: los atacantes pueden ejecutar código malintencionado durante la deserialización, exponiendo la aplicación a ataques remotos.
- Ataques por denegación de servicio: los datos malintencionados del Portapapeles pueden consumir recursos excesivos de memoria o CPU, lo que provoca bloqueos o inestabilidad.
- Riesgos de divulgación de información: los atacantes pueden extraer datos confidenciales de la memoria.
- Sin límites de seguridad: el formato es fundamentalmente no seguro y los valores de configuración no pueden protegerlo.
Habilite esta compatibilidad solo como puente temporal mientras actualiza la aplicación para usar las nuevas API seguras para tipos.
Instalación del paquete de compatibilidad
Agregue el paquete de compatibilidad no soportado BinaryFormatter a tu proyecto. Este paquete proporciona la compatibilidad necesaria en tiempo de ejecución para las operaciones BinaryFormatter.
<ItemGroup>
<PackageReference Include="System.Runtime.Serialization.Formatters" Version="10.0.0*-*"/>
</ItemGroup>
Nota:
Este paquete está marcado como no admitido y en desuso. Úselo solo para la compatibilidad temporal durante la migración.
Habilitación de la serialización no segura en el proyecto
Establezca la EnableUnsafeBinaryFormatterSerialization propiedad true en el archivo del proyecto. Esta propiedad indica al compilador que permita el uso de BinaryFormatter.
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryFormatterSerialization>
</PropertyGroup>
Sin esta configuración, la aplicación genera errores de compilación cuando intenta usar BinaryFormatter las API.
Configurar el conmutador de tiempo de ejecución de Windows Forms
Cree o actualice el archivo runtimeconfig.json de la aplicación para habilitar el interruptor del portapapeles específico de Windows Forms. Esta configuración permite que las operaciones del portapapeles se reviertan a BinaryFormatter cuando sea necesario.
{
"runtimeOptions": {
"configProperties": {
"Windows.ClipboardDragDrop.EnableUnsafeBinaryFormatterSerialization": true
}
}
}
Importante
Sin este interruptor de tiempo de ejecución específico, las operaciones del portapapeles no regresarán a BinaryFormatter aunque la compatibilidad con la serialización general esté habilitada. Este interruptor es necesario para la funcionalidad del Portapapeles específicamente de Windows Forms y WPF.
Implementar solucionadores de tipos enfocados en la seguridad
Incluso con BinaryFormatter habilitado, implemente solucionadores de tipos para restringir la deserialización a tipos aprobados explícitamente. Los solucionadores de tipos proporcionan su única defensa contra ataques de carga malintencionada.
Crear un solucionador de tipos 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
Utilizar el resolutor de tipos con operaciones del portapapeles
// 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
Directrices de seguridad para solucionadores de tipos
Siga estas directrices de seguridad esenciales al implementar solucionadores de tipos:
Usar listas de permitidos explícitas
- Rechazar de forma predeterminada: permitir solo tipos enumerados explícitamente.
- Sin caracteres comodín: evite la coincidencia de patrones o los permisos basados en espacios de nombres.
- Coincidencia exacta: requerir coincidencias exactas de cadena para los nombres de tipo.
Validar todas las entradas
- Validación del nombre de tipo: asegúrese de que los nombres de tipo coinciden con los formatos esperados.
- Restricciones de ensamblado: limite los tipos a ensamblados conocidos y de confianza.
- Comprobación de versiones: considere la posibilidad de tener en cuenta las restricciones de tipo específicas de la versión.
Manejo de tipos desconocidos de manera segura
- Lanzar excepciones: siempre lanzar para tipos no autorizados.
- Intentos de registro: considere la posibilidad de registrar intentos de acceso no autorizados.
- Mensajes claros de error: Proporcione motivos de rechazo específicos para la depuración.
Mantenimiento normal
- Auditar periódicamente: revise y actualice la lista de tipos permitidos.
- Quitar tipos sin usar: elimine los permisos de los tipos ya no necesarios.
- Decisiones de documento: mantenga una documentación clara de por qué se permite cada tipo.
Prueba de la configuración
Después de configurar la BinaryFormatter compatibilidad, pruebe la aplicación para asegurarse de que funciona correctamente:
- Comprobar las operaciones del Portapapeles: pruebe el almacenamiento y la recuperación de datos con los tipos personalizados.
- Solucionador de tipos de prueba: confirme que los tipos no autorizados se rechazan correctamente.
- Supervisar la seguridad: Vigile si hay intentos inesperados de resolución de tipos.
- Pruebas de rendimiento: asegúrese de que la resolución de tipos no afecta significativamente al rendimiento.
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
Planeamiento de la estrategia de migración
Aunque el soporte BinaryFormatter ofrece compatibilidad temporal, desarrolle un plan de migración para pasar a las nuevas API seguras para tipos:
- Identificar el uso: cataloge todas las operaciones del Portapapeles mediante tipos personalizados.
- Priorizar la migración: céntrese primero en las operaciones más sensibles a la seguridad.
- Actualizar incrementalmente: migre una operación cada vez para reducir el riesgo.
- Prueba exhaustiva: asegúrese de que las nuevas implementaciones proporcionan una funcionalidad equivalente.
- Quitar BinaryFormatter: Deshabilite la compatibilidad una vez completada la migración.
Limpieza de recursos
Una vez que haya migrado a las nuevas API del portapapeles con tipado seguro, quite la BinaryFormatter configuración para mejorar la seguridad.
- Quite la referencia del
System.Runtime.Serialization.Formatterspaquete. - Quite la
EnableUnsafeBinaryFormatterSerializationpropiedad de su archivo de proyecto. - Quite la configuración
Windows.ClipboardDragDrop.EnableUnsafeBinaryFormatterSerializationde suruntimeconfig.json. - Elimine las implementaciones de resolución de tipos que ya no son necesarias.
Contenido relacionado
.NET Desktop feedback